Linus Torvalds has never been shy about his skepticism toward parallelism. In one discussion he called the whole 'let's parallelize' push a huge waste of everybody's time. The quote is easy to remember, but the more interesting part of the exchange is technical: a defense of why reference counts must be atomic.
The argument began with a claim that sounds sensible. If an object is accessed by multiple threads through multiple paths, it generally needs its own mutex. If it does not have one, then its reference count would not need to be atomic; a lock on some higher-level object would be enough. In other words: the atomicity of the counter is just a consequence of a missing lock.
Torvalds rejected that framing. His point was that reference counts are often taken before the lock that protects the object's data. That timing matters, because object reference and object data are not protected by the same lock. They are two different problems, and they have completely different locking rules.
Object data locking is usually per object. Unless the system has serious scalability problems, each object can carry its own lock. In extreme cases, a larger external lock can cover many objects, up to a single global lock. But object referencing is mostly about finding an object, removing it, or freeing it. Is the object on a hash chain? In a tree? On a linked list? When the reference count reaches zero, the object data is not the thing that needs protection. Nothing else is using the object, so there is nothing left to protect. What needs protection is the path used to find the object.
That is why the lookup lock cannot simply live inside the object. By definition, you do not yet know which object you are dealing with; you are trying to look it up. So there is generally a lock that protects the lookup operation in some way, and the reference count needs to be atomic with respect to that lock.
It is true that such a lock can sometimes be enough. If there is only one way to find the object, then a single lookup lock may make non-atomic reference counts safe. But systems rarely have just one lookup path. An object may be pointed to by other objects, and those pointers are protected by the other objects' locks. Multiple objects may point to the same target. That is exactly why a reference count exists in the first place.
Once multiple lookup paths exist, there is no longer a single lock for lookup. Picture walking a graph of objects. Each pointer implies a reference to an object. As you move through the graph, you have to release the lock on the source object, and when you enter the next object you need to take a new reference to it. To avoid deadlocks, you generally cannot lock the new object before releasing the old one. In a complex graph, doing otherwise invites the classic ABBA deadlock: one thread locks A and wants B while another locks B and wants A. Someone has to let go.
Atomic reference counts make that walk possible. The sequence looks like this:
(a) You already hold a reference to object A, so you can lock A. (b) Once A is locked, the pointer from A to B is stable, and you know you have a reference to B because of that pointer. (c) You cannot take B's object lock while still holding A's lock without risking ABBA deadlock. (d) Increment B's atomic reference count. (e) Drop the lock on A; you are leaving A. (f) The reference you just took on B means B cannot disappear from under you even though A is unlocked. Now you can lock B.
That is the role atomic reference counts play. They are not there because programmers enjoy atomic operations. They are there because the counter is the bridge between releasing one lock and acquiring the next one. Yes, the overhead is real, and it is worth avoiding when the design allows it. If objects have a strict ordering—if you can walk from A to B but never from B to A—then there is no ABBA deadlock, and you can lock B while still holding A. In that case, non-atomic reference counts may be fine.
But if there is no forced ordering, and if an object can be reached through multiple paths, atomic reference counts are the simple and sane answer. A claim that they are unnecessary is a strong sign that the locking complexity has not been understood.
Concurrency is hard. The examples that make parallelism look easy tend to use simple arrays, and they never show allocation or freeing of objects. People who believe the future is massively parallel often have seen Linpack, parallel array sorting, and other demonstrations that contain no real complexity—and often have limited practical usefulness. Torvalds made the same point elsewhere: his reference-count example was the simple case, and the genuinely complex cases are worse. He does not believe the future is parallel. People who think compilers, programming languages, or better programmers will solve the problem are, in his view, far out to lunch.
Parallelism does work in simplified settings with clear interfaces and models. It appears in servers handling independent queries, in high-performance computing, in kernels, and in databases. Even there, people work hard to make it function at all, and they tend to limit their models to make them more amenable to parallel treatment. Database administrators, for example, arrange data to accommodate the limitations of the database. Other programming models can also work: neural networks are inherently very parallel, and they do not require smarter programmers to write them.
The reference count is a small integer. The reason it has to be atomic is not small at all.