Why can I not put a RefCell<> inside a mutex?

I have the following code :

And I was wondering why is it considered unsafe. It's not like the thing inside a Mutex can be accessed twice at the same time from two threads...

The problem is that a RefCell is !Send + !Sync, meaning you can't move it to another thread or let it be accessed from another thread by reference. However all static variables are required to be Sync because they can be accessed by any thread at any time.

These Send and Sync impls mean that a Mutex<T> is only Sync when T is Send.

It looks like those bounds were updated in this commit. You may want to read through the discussion on rust-lang/rust#23176 or rust-lang/rust#22574 for more the reasoning behind the changes.

Off the top of my head, one of the reasons you wouldn't want an unsafe impl<T> Sync for Mutex<T> is when thread-local variables are involved. Accessing methods on some T from a different thread could lead to logical errors because when the thread-local is used we expect data from the original thread (e.g. an index into a thread-local pool you are using for string interning), but actually find data from the currently executing thread.

1 Like

No, a RefCell is Send + !Sync. The mutex is not the problem here. The issue is the Arc.

You have an Mutex<Arc<RefCell<...>>>. An Arc is only Send if the contents are Sync, and since RefCell is Send + !Sync, and Arc<RefCell<...>> is !Send + !Sync.

Why is this bad? Well you can lock the mutex, clone the arc, unlock it again. Then clone the arc a bunch of times, send the arcs to different threads, and tadaa, access to the RefCell from multiple threads at the same time.

5 Likes

Oh, so the problem comes from the Arc ! Thanks !

Thanks @alice, I read the snippet as creating a Mutex<RefCell<T>> and went down the completely wrong rabbit hole :sweat_smile:

2 Likes