4 releases
Uses new Rust 2024
new 0.2.1 | Mar 13, 2025 |
---|---|
0.2.0 | Mar 12, 2025 |
0.1.1 | Mar 11, 2025 |
0.1.0 | Mar 7, 2025 |
#575 in Concurrency
451 downloads per month
20KB
334 lines
orchestrator_lock
provides a specialized mutex implementation for scenarios
where fine-grained control over mutex access is required. Unlike a standard
mutex where any code with a reference can attempt to acquire the lock, this
implementation separates the concerns of lock orchestration from lock usage.
Core Concepts
-
OrchestratorMutex: The central coordinator that owns the protected value and controls access to it.
-
Granter: A capability token that allows the orchestrator to grant lock access to a specific locker.
-
MutexLocker: The component that can acquire and use the lock, but only when explicitly granted access by the orchestrator.
-
MutexGuard: Provides access to the protected value, similar to a standard mutex guard.
Example
use tokio::time::Duration;
use orchestrator_lock::OrchestratorMutex;
#[tokio::main(flavor = "current_thread")]
async fn main() {
// Create a shared counter with initial value 0
let mut orchestrator = OrchestratorMutex::new(0);
// Create two granter/locker pairs
let (mut granter1, mut locker1) = orchestrator.add_locker();
let (mut granter2, mut locker2) = orchestrator.add_locker();
// Task 1: Increments by 1 each time
let task1 = tokio::spawn(async move {
let expected = [0, 2, 6];
for i in 0..3 {
if let Some(mut guard) = locker1.acquire().await {
assert_eq!(*guard, expected[i]);
*guard += 1;
tokio::time::sleep(Duration::from_millis(10)).await;
}
}
locker1
});
// Task 2: Multiplies by 2 each time
let task2 = tokio::spawn(async move {
let expected = [1, 3, 7];
for i in 0..3 {
if let Some(mut guard) = locker2.acquire().await {
assert_eq!(*guard, expected[i]);
*guard *= 2;
tokio::time::sleep(Duration::from_millis(10)).await;
}
}
locker2
});
// Orchestration: Alternate between the two tasks
for i in 0..3 {
// Grant access to task 1
let task1_holding = orchestrator.grant_access(&mut granter1).await.unwrap();
task1_holding.await;
// Grant access to task 2
let task2_holding = orchestrator.grant_access(&mut granter2).await.unwrap();
task2_holding.await;
}
assert_eq!(*orchestrator.acquire().await, 14);
// Clean up
let _ = task1.await.unwrap();
let _ = task2.await.unwrap();
}
Dependencies
~2.7–8.5MB
~71K SLoC