Crates.io | saa |
lib.rs | saa |
version | 3.0.2 |
created_at | 2025-08-07 19:35:11.047117+00 |
updated_at | 2025-08-29 21:46:23.932572+00 |
description | Low-level synchronization primitives that provide both synchronous and asynchronous interfaces |
homepage | |
repository | https://github.com/wvwwvwwv/synchronous-and-asynchronous/ |
max_upload_size | |
id | 1785708 |
size | 172,100 |
Low-level synchronization primitives that provide both synchronous and asynchronous interfaces.
Loom
support: features = ["loom"]
.saa::Lock
is a low-level shared-exclusive lock that provides both synchronous and asynchronous interfaces. Synchronous locking methods such as lock_sync
or share_sync
can be used with their asynchronous counterparts, lock_async
or share_async
, at the same time. saa::Lock
implements a heap-allocation-free fair wait queue that is shared among both synchronous and asynchronous methods.
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());
};
saa::Semaphore
is a synchronization primitive that allows a fixed number of threads to access a resource concurrently.
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());
};
saa::Gate
is an unbounded barrier that can be open or sealed manually whenever needed.
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();
}
Use of synchronous methods in an asynchronous context may lead to a deadlock. Suppose a scenario where an asynchronous runtime provides two threads executing three tasks.
task-0: share-waiting / pending
|| task-1: "synchronous"-lock-waiting
.task-2: release-lock / ready: wake-up task-0
-> task-2: lock-waiting / pending
.In the above example, task-0
logically has acquired a shared lock which was transferred from task-2
, however, it may remain in the task queue indefinitely, depending on the scheduling policy of the asynchronous runtime.