Rust lock
2025-05-21
pub static PINGCANG_LOCK: Lazy<Mutex<()>> = Lazy::new(|| Mutex::new(()));
let _lock = PINGCANG_LOCK
.lock()
.map_err(|_| BinanceError::Other("Failed to acquire lock".into()))?;
Here’s a detailed breakdown of what happens with your lock implementation in Rust:
Lock Acquisition Process
- Static Mutex Initialization:
pub static PINGCANG_LOCK: Lazy<Mutex<()>> = Lazy::new(|| Mutex::new(()));- The
Lazyensures theMutexis initialized on first use (thread-safe initialization) - Creates a mutex protecting a unit value
()(common pattern for pure synchronization)
- The
- Lock Attempt:
let _lock = PINGCANG_LOCK .lock() .map_err(|_| BinanceError::Other("Failed to acquire lock".into()))?;
Step-by-Step Execution Flow
- First Thread Arrives:
- Checks
PINGCANG_LOCK(unlocked) - Immediately acquires the lock
lock()returnsOk(MutexGuard)_locknow holds the guard
- Checks
- Second Thread Arrives While Locked:
- Attempts to call
lock() - If the mutex is still held by first thread:
- Blocks (waits) until the first thread releases the lock
- No CPU spin - uses OS-level blocking
- Once first thread drops
_lock(goes out of scope):- Wakes waiting thread
- Second thread acquires lock
- Attempts to call
- Poisoned Mutex Case:
- If a previous thread panicked while holding the lock:
lock()returnsErr(PoisonError)- Your code maps this to
BinanceError::Other
- Lock Release:
- Automatically occurs when
_lockgoes out of scope - Implemented via
Droptrait onMutexGuard
- Automatically occurs when
Key Characteristics
- Blocking Behavior:
- The
.lock()call will:- Return immediately if unlocked
- Block (wait) if currently locked
- No busy-waiting (efficient thread suspension)
- The
- Error Handling:
- Your version properly handles:
- Poisoning (thread panic during lock)
- Converts to your error type via
?operator
- Your version properly handles:
- RAII Guarantees:
- The lock cannot be accidentally held indefinitely
- Release is tied to
_lock’s scope
Visual Timeline
Thread 1: [lock()] -> [Critical Section] -> [drop(_lock)]
Thread 2: [lock() blocks] -> [Acquires lock]
When To Use This Pattern
This is ideal for:
- Protecting short critical sections
- Simple exclusive access requirements
- Cases where poisoning should fail the operation
For async contexts, you’d want tokio::sync::Mutex instead.