15 releases (1 stable)

Uses new Rust 2021

new 1.0.0 Jul 1, 2022
0.11.0 Jun 30, 2022
0.10.0 Jun 29, 2022
0.5.0 Mar 14, 2022

#114 in Concurrency

Download history 50/week @ 2022-03-12 29/week @ 2022-03-19 6/week @ 2022-03-26 10/week @ 2022-04-02 8/week @ 2022-04-09 3/week @ 2022-04-16 14/week @ 2022-04-23 39/week @ 2022-04-30 39/week @ 2022-05-07 88/week @ 2022-05-14 20/week @ 2022-05-21 67/week @ 2022-05-28 42/week @ 2022-06-04 6/week @ 2022-06-11 103/week @ 2022-06-18 66/week @ 2022-06-25

226 downloads per month
Used in rcell

MIT/Apache

22KB
418 lines

ShardedMutex, atomic Everything

This library provides global locks for (pseudo-) atomic access to data without memory overhead per object. Concurrency is improved by selecting a Mutex from a pool based on the Address of the object to be locked.

Even being sharded, these Mutexes act still as global and non-recursive locks. One must not lock another object while a lock on the same type/domain is already hold, otherwise deadlocks will happen.

There is one pool of mutexes per guarded type, thus it is possible to lock values of different types at the same time. Further a 'multi_lock' API allows to obtain locks on multiple objects of the same type at the same time.

This pool of mutexes per types comes with a cost. In the current implementation each pool needs 256 bytes. Thus using ShardedMutex makes only sense for types when significantly more than 256 instances are to be expected.

Same types may have different locking domains using type tags.

Provides pseudo atomic access for types that implement Copy and PartialEq.

In debug builds a deadlock detector is active which will panic when one tries to lock objects from the same type/domain while already holding a lock.

Example usage:

use sharded_mutex::ShardedMutex;

// create 2 values that need locking
let x = ShardedMutex::new(123);
let y = ShardedMutex::new(234);

// a single lock
assert_eq!(*x.lock(), 123);

// Multiple locks
let mut guards = ShardedMutex::multi_lock([&x, &y]);

assert_eq!(*guards[0], 123);
assert_eq!(*guards[1], 234);

// can write as well
*guards[1] = 456;

// unlocks
drop(guards);

// lock again
assert_eq!(*y.lock(), 456);

// Pseudo atomic access
use sharded_mutex::PseudoAtomicOps;

x.store(&234);
assert_eq!(x.load(), 234);

let mut swapping = 345;
x.swap(&mut swapping);
assert_eq!(swapping, 234);
assert_eq!(x.load(), 345);

assert!(!x.compare_and_set(&123, &456));
assert!(x.compare_and_set(&345, &456));
assert_eq!(x.load(), 456);

Dependencies

~0.5–5.5MB
~87K SLoC