Expand description
§Synchronous and Asynchronous Synchronization Primitives
Low-level synchronization primitives providing both asynchronous and synchronous interfaces.
§Features
- Provides both asynchronous and synchronous interfaces.
Loom
support:features = ["loom"]
.
§Lock
saa::Lock
is a low-level shared-exclusive lock providing both asynchronous and synchronous interfaces. Synchronous locking methods such as lock_sync
and share_sync
can be used alongside their asynchronous counterparts lock_async
and share_async
simultaneously. saa::Lock
implements a heap-allocation-free fair wait queue shared between both synchronous and asynchronous methods.
§Examples
use saa::Lock;
let lock = Lock::default();
lock.lock_sync();
assert!(!lock.try_lock());
assert!(!lock.try_share());
assert!(!lock.release_share());
assert!(lock.release_lock());
async {
lock.share_async();
assert!(lock.release_share());
};
§Semaphore
saa::Semaphore
is a synchronization primitive that allows a fixed number of threads to access a resource concurrently.
§Examples
use saa::Semaphore;
let semaphore = Semaphore::default();
semaphore.acquire_many_sync(Semaphore::MAX_PERMITS - 1);
assert!(semaphore.try_acquire());
assert!(!semaphore.try_acquire());
assert!(semaphore.release());
assert!(!semaphore.release_many(Semaphore::MAX_PERMITS));
assert!(semaphore.release_many(Semaphore::MAX_PERMITS - 1));
async {
semaphore.acquire_async().await;
assert!(semaphore.release());
};
§Gate
saa::Gate
is an unbounded barrier that can be opened or sealed manually as needed.
§Examples
use std::sync::Arc;
use std::thread;
use saa::Gate;
use saa::gate::State;
let gate = Arc::new(Gate::default());
let mut threads = Vec::new();
for _ in 0..4 {
let gate = gate.clone();
threads.push(thread::spawn(move || {
assert_eq!(gate.enter_sync(), Ok(State::Controlled));
}));
}
let mut cnt = 0;
while cnt != 4 {
if let Ok(n) = gate.permit() {
cnt += n;
}
}
for thread in threads {
thread.join().unwrap();
}
§Notes
Using synchronous methods in an asynchronous context may lead to deadlocks. Consider a scenario where an asynchronous runtime uses two threads to execute three tasks.
- ThreadId(0):
task-0: share-waiting / pending
||task-1: "synchronous"-lock-waiting
. - ThreadId(1):
task-2: release-lock / ready: wake-up task-0
->task-2: lock-waiting / pending
.
In this example, task-0
has logically acquired a shared lock transferred from task-2
; however, it may remain in the task queue indefinitely depending on the asynchronous runtime’s scheduling policy.
§Changelog
Re-exports§
pub use gate::Gate;
Modules§
- gate
Gate
is a synchronization primitive that blocks tasks from entering a critical section until they are allowed to do so.