16 releases (4 breaking)

0.5.4 May 26, 2022
0.5.3 Mar 23, 2022
0.4.2 Nov 28, 2021
0.3.3 Nov 6, 2021
0.1.0 Oct 31, 2021

#558 in Concurrency

MIT license

9KB
159 lines

with_lock

Deadlock freedom

Using with_lock? Share it in the discussion!

Docs

This crate provides a simple way of managing Mutex's, and freeing your code from deadlocks. It is powered by parking_lot.

Example

Say you have this code:

use std::sync::Mutex;

fn main() {
    let a = Mutex::new(2);
    let b = Mutex::new(3);
    let a_lock = a.lock().unwrap();
    let b_lock = b.lock().unwrap();
    assert_eq!(*a_lock + *b_lock, 5);
    let a_lock_2 = a.lock().unwrap();
    let b_lock_2 = b.lock().unwrap();
    assert_eq!(*a_lock_2 + *b_lock_2, 5);
}

That code will run the first assert_eq! fine, but the second wouldn't assert due to a deadlock.

However, we can prevent this by replacing our manual calls of .lock with .with_lock. Code that wouldn't error would look something like:

use with_lock::WithLock;

fn main() {
    let a = WithLock::<i64>::new(2);
    let b = WithLock::<i64>::new(3);
    let a_lock = a.with_lock(|s| *s);
    let b_lock = b.with_lock(|s| *s);
    assert_eq!(a_lock + b_lock, 5);
    let a_lock_2 = a.with_lock(|s| *s);
    let b_lock_2 = b.with_lock(|s| *s);
    assert_eq!(a_lock_2 + b_lock_2, 5);
}

This test would pass, and both assertions would be fulfilled. This is an example of how a dead lock was prevented.

Cell like API

with_lock provides a custom Cell like API powered by a Mutex.

use with_lock::MutexCell;

fn main() {
    let a = MutexCell::new(2);
    let b = MutexCell::new(3);
    let a_locked = a.get();
    let b_locked = b.get();
    assert_eq!(a_locked + b_locked, 5);
    let a_lock_2 = a.get();
    let b_lock_2 = b.get();
    assert_eq!(a_lock_2 + b_lock_2, 5);
}

For more examples, see the examples directory. They can be run by cloning this repository and running cargo run --example <example_name>.

Dependencies

~0.4–5MB
~11K SLoC