Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Your first diagnosis

This example deliberately creates the classic two-lock cycle.

1. Start the detector

#![allow(unused)]
fn main() {
extern crate deloxide;
use deloxide::{DeadlockInfo, Deloxide};

Deloxide::new()
    .callback(|report: DeadlockInfo| {
        eprintln!("source: {:?}", report.source);
        eprintln!("threads: {:?}", report.thread_cycle);
        eprintln!("waited locks: {:?}", report.thread_waiting_for_locks);
    })
    .start()
    .expect("start Deloxide");
}

Initialize Deloxide before creating the tracked locks and worker threads.

2. Create opposite lock order

#![allow(unused)]
fn main() {
extern crate deloxide;
use deloxide::{Mutex, thread};
use std::sync::{Arc, Barrier};
let left = Arc::new(Mutex::new(()));
let right = Arc::new(Mutex::new(()));
let barrier = Arc::new(Barrier::new(2));
let left_a = Arc::clone(&left);
let right_a = Arc::clone(&right);
let barrier_a = Arc::clone(&barrier);
let left_b = Arc::clone(&left);
let right_b = Arc::clone(&right);
let barrier_b = Arc::clone(&barrier);
let first = thread::spawn(move || {
    let _left = left_a.lock();
    barrier_a.wait();
    let _right = right_a.lock();
});

let second = thread::spawn(move || {
    let _right = right_b.lock();
    barrier_b.wait();
    let _left = left_b.lock();
});
let _ = (first, second);
}

The barrier makes both threads keep their first lock before requesting the second. Deloxide sees the active cycle and calls the callback.

3. Read the result

source: WaitForGraph
threads: [ThreadId(2), ThreadId(3)]
waited locks: [(ThreadId(2), LockId(2)), (ThreadId(3), LockId(1))]

Fix the program by choosing one lock order and using it on every path.

Run the complete example:

cargo run --example diagnose_deadlock

Source: examples/diagnose_deadlock.rs. Continue with Reading a report for self-deadlocks, RwLock, condition variables, and missing evidence.