Safe-threading and async HashMap

Hi!

I have such struct for example:

use tokio::sync::Mutex;
use create fxhash::FxHashMap;

struct StructWithState {
    state: Arc<Mutex<FxHashMap<String, String>>> // Or DashMap without Mutex
}

I have different mutation in async way further and both DashMap and Mutex + FxHashMap have deadlocks and other things.

Could you please give me some advice what is a better to use in such case?

If you are using tokio's Mutex and you still have deadlocks then there's likely nothing else to do than to re-architect your code to avoid such deadlocks.

Have you checked that the deadlocks actually come from taking this lock? What is the thread/task that took the lock doing?

In general try to avoid waiting on anything to become available (e.g. taking another lock, reading from a channel, etc etc) while you are holding a lock to this map. If you can avoid holding the lock across .awaits it's even better.

3 Likes

Lock guards only unlock when they're dropped, by default that's at the end of the scope, e.g. the end of the function.
It's best to use dedicated blocks or drop to reduce their lifetime, see Mutex examples section.

1 Like

Is it better to use DashMap without Mutex or Mutex + FxHashMap in async environment? What are the best practices in such case?

For example, I have a lot of mutation of state and it can happen in one thread and in different async tasks. And I think that even in one thread I can have a situation when I lock the state and it can lead to deadlock even inside one thread. Do I understand it correctly?

And I think that even in one thread I can have a situation when I lock the state and it can lead to deadlock even inside one thread. Do I understand it correctly?

A deadlock occurs when A is holding the lock and B tries to acquire the lock and A is waiting for B and B can't acquire it until A releases it.
A and B can be on different threads or - if the lock is not reentrant - separate lock-acquisitions the same thread (e.g. one method calling another).

There are also more complex deadlock scenarios involving multiple locks forming a cycle, this easily happens when acquiring multiple locks in different orders.

Dashmap is a sharded maps, essentially different ranges of the map are protected by different locks. This allows concurrent writers to different parts of the map to still make progress. This can prevent some specific deadlock scenarios but not in the general case they can still occur.

You can try lock-free concurrent data structures like crossbeam's SkipMap if you want concurrent modification without deadlocks, at the expense of not providing mutable references to values.

2 Likes

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.