Rust, Mutexes, and Mutating Data in Re-entrant Mutexes

TL;DR it is possible to have re-entrant mutexes in Rust, and mutate data. This article summarizes what to do, but a simple code example is available Read the code, it’s very easy. The example is fully commented and uses println!() statements to explain everything written below.

Rust offers a variety of tools for multi threaded and concurrent programming including mutexes. But the mutexes included in the standard library leave a lot to be desired. If you come from a Java or C background, for instance, you’re probably familiar with re-entrant mutexes. These mutexes can be locked numerous times by the same thread without deadlocking. That feature can often simplify multi-threaded or concurrent code significantly.

Thankfully, the parking_lot crate solves that problem. Swap out std::sync::Mutex for parking_lot::ReentrantMutex and you have an an almost drop-in replacement that’s fully re-entrant. I say “almost” because sync::Mutex.lock() returns a Result<> and requires an extra .unwrap(). But that’s really just nitpicking.

Unfortunately, parking_lot::ReentrantMutex only works for immutable data. There is no way of directly obtaining a mutable reference to the data protected by parking_lot’s ReentrantMutex. So what do you do when you need to change the data?

It’s RefCell to the rescue! Your protected data will likely end up looking something like this:

Your site doesn’t include support for the SyntaxHighlighter Evolved block. You can try installing the block, convert it to a Custom HTML block, or remove it entirely. Install SyntaxHighlighter EvolvedKeep as HTML

let shared_data = Arc::new(ReentrantMutex::new(RefCell::new(55)));

RefCell implements borrowing rules at runtime, not compile time. So data mutation is allowed, but the rules must be followed or else your code will panic!().

The sample project shows regular mutexes (from the parking_lot crate, but std::sync::Mutex can be used as well), re-entrant mutexes for immutable data, and finally re-entrant mutexes combined with RefCell to allow for data mutation.

Re-entrant mutexes have a performance penalty when compared to regular mutexes, but they simplify multi-threaded code enough that I consider it to be a worthwhile tradeoff, unless every nanosecond counts.