Async lock options

Do I understand correctly that the benefit of using Arc<RwLock<some-type>> instead of Arc<Mutex<some-type>> is that with the former you can have concurrent read access from multiple threads, but the latter does not allow that?

Is using parking_lot::RwLock typically preferred over using std::sync::RwLock?

Yes, that's correct, but since you have async in the title, I feel the need to point out that the only reason that the std or parking_lot mutex is ok to use in async code despite being blocking is that you will typically only block the thread for a very short amount of time if you make sure to unlock it quickly.

A blocking RwLock does not have this advantage. It is very easy to block writers for a long time with an RwLock if there are lots of readers all the time, even if no individual reader locks it for a long time.

You may like the Tokio tutorial's article on shared state, which covers use of blocking mutexes in async code.

Regarding std vs parking-lot, the parking-lot crate is typically faster.

1 Like

Is parking_lot::Mutex typically preferred over std::sync::Mutex?

I guess. Realistically you will be fine either way.

Are there situations where it makes more sense to put the Arc inside the lock like Mutex<Arc<some-type>> or RwLock<Arc<some-type>>?

No, at least not directly inside. To understand why, you need to understand that the real difference between immutable and mutable is whether you have exclusive access to the thing. The entire purpose of a Mutex/RwLock is to allow you to obtain exclusive (i.e. mutable) access to the thing behind the lock, even though the lock is shared (i.e. you don't have exclusive access to the lock itself).

However an Arc<T> can be cloned, giving out multiple handles to the same thing. So, even if you have exclusive access to the Arc<T>, you only have shared access to the T, as it might not be the only arc.

So in short:

  1. An Arc<T> gives shared-only access to T.
  2. An Mutex<Arc<T>> gives shared-only access to T.

What does make sense is to have Mutex<HashMap<String, Arc<Value>>>. This makes sense because you can:

  1. Lock the mutex.
  2. Access some key in the map, calling clone on the Arc.
  3. Unlock the mutex.
  4. Continue to access the value in the map through your clone of the Arc.

Of course, the value stored inside the HashMap becomes immutable if you do this, since there may be other arcs to the value. However to change it, you can replace the Arc with a new Arc, letting anyone still looking at the value continue to see the old value, but making any future accesses see the new value.

2 Likes

It looks like the parking_lot version of RwLock implements a fairness policy takes care of the situation you described where readers just keep coming and prevent any writers from acquiring a lock.

Ah, I didn't know that. If the RwLock you are using is fair, then it is ok to use in async code, with the same cavaets as with the mutex.

1 Like