Mutex vs RwLock
Reach for `Mutex<T>` when you need exclusive access to data and the critical section is short. `RwLock<T>` allows many simultaneous readers or one exclusive writer — use it when reads vastly outnumber writes. Both lock methods return a `LockResult`; the Err variant indicates the lock is poisoned because a previous holder panicked, in which case you can decide whether the data is still safe to use via `into_inner()`.
Atomics for lock-free state
`std::sync::atomic` exposes lock-free integer and pointer types: `AtomicBool`, `AtomicU64`, `AtomicPtr`, etc. Every operation takes an `Ordering` parameter — start with `Ordering::SeqCst` until you understand the memory model. Atomics are dramatically faster than a `Mutex` around a single integer for high-contention counters and flags.
For deeper background, see a complete cheat-sheet of std collection complexities for the broader context behind this section.
Channels (mpsc)
`std::sync::mpsc::channel` returns a multi-producer single-consumer channel: any number of `Sender<T>` instances can send to one `Receiver<T>`. Senders are cloneable; the receiver is not. The channel is unbounded; for back-pressure use `sync_channel(capacity)`. For multi-consumer or async channels reach for the `crossbeam-channel` or `tokio::sync::mpsc` crates respectively.
OnceLock and lazy globals
`OnceLock<T>` is the modern replacement for `lazy_static!` — a thread-safe slot that can be initialised exactly once. Define it as a `static` and call `get_or_init` on first access. For non-thread-safe lazy initialisation use `OnceCell` from `std::cell`.
For deeper background, see the official Rust API guidelines for module-level design for the broader context behind this section.
Sharing ownership: Arc and Weak
`Arc<T>` provides atomically reference-counted shared ownership across threads. Combine with `Mutex` or `RwLock` for shared mutable state. `Weak<T>` is a non-owning observer that can't prevent the value from being dropped — break Arc cycles with Weak to avoid memory leaks.