Rust Concurrency Primitives
Use this skill to design thread-based Rust concurrency with explicit ownership, sharing, and synchronization. Prefer the simplest primitive that matches the coordination requirement before adding shared mutable state.
Core Workflow
- Classify the work: independent fork-join, producer/consumer pipeline, shared state, one-time initialization, or low-level atomic coordination.
- Prefer owned data per thread. Add shared ownership only when data must be observed or mutated by multiple threads.
- Use
std::thread::scopewhen child threads can borrow stack data and must finish before the function returns. - Use channels for ownership transfer and pipelines. Use
Arc<Mutex<T>>orArc<RwLock<T>>only when shared state is the clearer model. - Keep lock scopes short and never call user-controlled or blocking code while holding a lock unless that is the invariant being protected.
- Use
OnceLockorLazyLockfor thread-safe one-time initialization instead of ad hoc global mutable state. - Treat atomics as a specialized tool. Use
SeqCstby default until a weaker ordering is justified and documented.
Primitive Selection
Read references/threading-shared-state.md before introducing a new shared
state primitive or reviewing deadlock-prone code.
| Need | Primitive |
|---|---|
| Borrow local data into short-lived threads | std::thread::scope |
| Transfer work or results | std::sync::mpsc or project channel crate |
| Shared read/write state | Arc<Mutex<T>> |
| Many readers, rare writers | Arc<RwLock<T>> |
| Wait for condition changes | Condvar with Mutex |
| One-time global initialization | LazyLock or OnceLock |
| Counters, flags, lock-free coordination | std::sync::atomic |
Safety And Review Rules
- Require
Sendfor values crossing thread boundaries andSyncfor shared references used from multiple threads. - Decide whether poisoning should propagate panic or recover with
PoisonError::into_inner. - Establish a lock ordering when more than one lock can be acquired.
- Prefer
Arc::clone(&value)overvalue.clone()when the cloned value is an ownership handle and readability matters. - Use Rayon for data parallel iteration when the problem is pure CPU data parallelism and the project already accepts that dependency.
Tests
- Add deterministic tests around final state, message counts, and shutdown.
- Use barriers, channels, or scoped threads to coordinate tests; avoid sleeps.
- Add at least one test for panic, dropped sender/receiver, or cancellation behavior when the code depends on it.
Source: hashgraph-online/awesome-codex-plugins → plugins/LVTD-LLC/skills/skills/rust-concurrency-primitives/SKILL.md