-
Notifications
You must be signed in to change notification settings - Fork 143
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Ways to debug deadlocks #243
Comments
Hey, so this can be a bit tricky. Usually I just fire up lmdb and dump the backtraces of every thread when they happen and go through their callstacks. Does that help? |
Thanks I will give that a try. For tokio::sync::RwLock the |
Could something like this be integrated into Dashmap for debugging purposes? https://lib.rs/crates/no_deadlocks |
Do you have any references or doc for that (lmdb)? |
I wanted to give https://github.com/BurtonQin/lockbud a try but it does not work on Mac OS (https://github.com/BurtonQin/lockbud). Which approach do you normally take to get the backtraces of each thread? |
Sorry, I made a typo. I rely on the |
I ran thread #8, name = 'tokio-runtime-worker'
frame #0: 0x000000019209e5e4 libsystem_kernel.dylib`__psynch_cvwait + 8
frame #1: 0x00000001920da638 libsystem_pthread.dylib`_pthread_cond_wait + 1232
frame #2: 0x00000001010708cc butterbrot`dashmap::lock::RawRwLock::lock_exclusive_slow::h3eceab46f26c3724 + 624
frame #3: 0x0000000100a4e75c butterbrot`butterbrot_rust::core::load_and_store::_$u7b$$u7b$closure$u7d$$u7d$::h07759cdff2954bfc + 3948 Is it correct that there must be another |
Hi @xacrimon .
Might this be the root cause of my issue cause I have something like: let account = dm.get_mut(&account);
if let Some(mut a) = account {
a.value_mut().save("update").await; // <-- Holding accross await point
} |
Reproducer #[tokio::test]
async fn dashmap_async_test() {
struct CanAsyncSave {};
impl CanAsyncSave {
pub async fn save(&mut self) {
tokio::time::sleep(Duration::from_millis(1)).await;
}
}
let dm: Arc<DashMap<String, CanAsyncSave>> = Default::default();
let dm_clone = dm.clone();
tokio::task::spawn(async move {
for _ in 0..100 {
let mut entry = dm_clone.get_mut("1").unwrap();
let val = entry.value_mut();
val.save().await;
}
});
for _ in 0..100 {
dm.insert("1".into(), CanAsyncSave {});
let mut entry = dm.get_mut("1").unwrap();
let val = entry.value_mut();
val.save().await;
}
} |
Sounds pretty similar to if you were using std mutex, parking_lot, etc., where you want to avoid locking across an await. In cases like that i would just stick with a lock that is await aware, avoid awaiting on it. or change functionality around |
This very helpful post covers how to make Dashmap not deadlock in async code: https://draft.ryhl.io/blog/shared-mutable-state/ It also explains why the compiler does not warn about these deadlocks. The gist is never to await in anything while holding a lock. A lock is taken when accessing the Dashmap, and released when the guard is dropped... If I got it right that is. The recommended approach is to never access Dashmap directly in async code, but through a convenience wrapper. |
Ran into this as I was looping over my DashMap's iterator and performing an async operation within it. This deadlocked my app unpredictably. My solution was to collect the values from the iterator synchronously first, then loop over the collected values to perform my async operation. |
I was reading Alice's blog that was mentioned in this thread. Alice points out that the compiler doesn't complain about a holding guard (or reference) over an I wonder if |
Hi!
What is the recommended approach to debug dead locks associated with Dashmap? Is there some tooling for that purpose?
Thanks
The text was updated successfully, but these errors were encountered: