mirror of
https://github.com/bertptrs/tracing-mutex.git
synced 2025-12-25 20:50:32 +01:00
The example originally showed a certain deadlock, which was not as clear as it could be. The new version shows intentionally racy code that may result in a successful execution but may also deadlock.
63 lines
2.1 KiB
Rust
63 lines
2.1 KiB
Rust
//! Show what a crash looks like
|
|
//!
|
|
//! This shows what a traceback of a cycle detection looks like. It is expected to crash when run in
|
|
//! debug mode, because it might deadlock. In release mode, no tracing is used and the program may
|
|
//! do any of the following:
|
|
//!
|
|
//! - Return a random valuation of `a`, `b`, and `c`. The implementation has a race-condition by
|
|
//! design. I have observed (4, 3, 6), but also (6, 3, 5).
|
|
//! - Deadlock forever.
|
|
//!
|
|
//! One can increase the SLEEP_TIME constant to increase the likelihood of a deadlock to occur. On
|
|
//! my machine, 1ns of sleep time gives about a 50/50 chance of the program deadlocking.
|
|
use std::thread;
|
|
use std::time::Duration;
|
|
|
|
use tracing_mutex::stdsync::Mutex;
|
|
|
|
fn main() {
|
|
let a = Mutex::new(1);
|
|
let b = Mutex::new(2);
|
|
let c = Mutex::new(3);
|
|
|
|
// Increase this time to increase the likelihood of a deadlock.
|
|
const SLEEP_TIME: Duration = Duration::from_nanos(1);
|
|
|
|
// Depending on random CPU performance, this section may deadlock, or may return a result. With
|
|
// tracing enabled, the potential deadlock is always detected and a backtrace should be
|
|
// produced.
|
|
thread::scope(|s| {
|
|
// Create an edge from a to b
|
|
s.spawn(|| {
|
|
let a = a.lock().unwrap();
|
|
thread::sleep(SLEEP_TIME);
|
|
*b.lock().unwrap() += *a;
|
|
});
|
|
|
|
// Create an edge from b to c
|
|
s.spawn(|| {
|
|
let b = b.lock().unwrap();
|
|
thread::sleep(SLEEP_TIME);
|
|
*c.lock().unwrap() += *b;
|
|
});
|
|
|
|
// Create an edge from c to a
|
|
//
|
|
// N.B. the program can crash on any of the three edges, as there is no guarantee which
|
|
// thread will execute first. Nevertheless, any one of them is guaranteed to panic with
|
|
// tracing enabled.
|
|
s.spawn(|| {
|
|
let c = c.lock().unwrap();
|
|
thread::sleep(SLEEP_TIME);
|
|
*a.lock().unwrap() += *c;
|
|
});
|
|
});
|
|
|
|
println!(
|
|
"{}, {}, {}",
|
|
a.into_inner().unwrap(),
|
|
b.into_inner().unwrap(),
|
|
c.into_inner().unwrap()
|
|
);
|
|
}
|