Mental model for Rc/Arc

I don't know about you, but for the longest time I had a hard time remembering why we need to wrap types like Mutex, RwLock or Atomic* in an Arc.
I just had a neat idea for how to "visualize" what Rc and Arc are. Maybe it can help others that struggle with it as well.

Basically it boils down to
Arc<T> ~ &T

Let's elaborate with Mutex as an example. The idea of a Mutex<R> is that we can share it through a reference &Mutex<R> across threads because it uses interior mutability and synchronization mechanisms to make sure we don't get data races. The problem with a reference like &Mutex<R> is that in general we cannot send it freely between threads. You usually get livetime problems unless you can use a thread::scope.
Now imagine Arc<T> as a fancier version of a reference &T. It basically is a reference that circumvents lifetime problems by owning the reffered-to value. We create the first one with Arc::new() and every further one with Arc::clone(). So using Arc there is now no problem sending Arc<Mutex<P>> between threads.

Of course, this is not really something new. But this image
Arc<T> ~ &T
has somehow been missing from my brain.

1 Like

Yes, that sounds accurate. An Arc<T> is very similar to an immutable reference.


I also feel like Arc<T> is "like" &T (the common property is that they both implement Deref<Target=T>). And when it comes to Mutex<T>, it helps to remember it is a Send/Sync version of a RefCell.

So Arc<Mutex<T>> is fulfilling the role of a reference to a cell (where the reference is in fact a smart pointer that solves some ownership issues[1] and the cell is a Send/Sync version of RefCell).

That "cell" allows turning the shared reference into a mutable one, e.g. to replace the value or to invoke methods taking &mut self, which wouldn't be possibe with a shared reference otherwise.

  1. Not that Arc doesn't solve all problems which garbage collection ncan solve because it will leak memory if you construct cycles. ↩ī¸Ž

1 Like
Shared Mutable
Strictly scoped &T &mut T or T
Unclear scope - single thread Rc<T> Rc<RefCell<T>>>
Unclear scope - multithread Arc<T> Arc<Mutex<T>>>