skills/m07-concurrency/SKILL.md
CRITICAL: Use for concurrency/async. Triggers: E0277 Send Sync, cannot be sent between threads, thread, spawn, channel, mpsc, Mutex, RwLock, Atomic, async, await, Future, tokio, deadlock, race condition
npx skillsauth add thurbeen/rust-skills m07-concurrencyInstall this skill globally with one command. Works with Claude Code, Cursor, and Windsurf.
3 of 9 scanners reported clean
Some scanners were skipped, did not run, or reported a non-clean status. Review each row below.
Layer 1: Language Mechanics
Is this CPU-bound or I/O-bound, and what's the sharing model?
Before choosing concurrency primitives:
| Error | Don't Just Say | Ask Instead | |-------|----------------|-------------| | E0277 Send | "Add Send bound" | Should this type cross threads? | | E0277 Sync | "Wrap in Mutex" | Is shared access really needed? | | Future not Send | "Use spawn_local" | Is async the right choice? | | Deadlock | "Reorder locks" | Is the locking design correct? |
Before adding concurrency:
What's the workload?
What's the sharing model?
What are the Send/Sync requirements?
CRITICAL: Don't just fix the error. Trace UP to find domain constraints.
| Context Keywords | Load Domain Skill | Key Constraint | |-----------------|-------------------|----------------| | Web API, HTTP, axum, actix, handler | domain-web | Handlers run on any thread | | trading, payment | domain-fintech | Audit + thread safety | | gRPC, kubernetes, microservice | domain-cloud-native | Distributed tracing | | CLI, terminal, clap | domain-cli | Usually single-thread OK |
"Rc cannot be sent between threads" in Web API context
↑ DETECT: "Web API" → Load domain-web
↑ FIND: domain-web says "Shared state must be thread-safe"
↑ FIND: domain-web says "Rc in state" is Common Mistake
↓ DESIGN: Use Arc<T> with State extractor
↓ IMPL: axum::extract::State<Arc<AppConfig>>
"Send not satisfied for my type"
↑ Ask: What domain is this? Load domain-* skill
↑ Ask: Does this type need to cross thread boundaries?
↑ Check: m09-domain (is the data model correct?)
| Situation | Trace To | Question | |-----------|----------|----------| | Send/Sync in Web | domain-web | What's the state management pattern? | | Send/Sync in CLI | domain-cli | Is multi-thread really needed? | | Mutex vs channels | m09-domain | Shared state or message passing? | | Async vs threads | m10-performance | What's the workload profile? |
From design to implementation:
"Need parallelism for CPU work"
↓ Use: std::thread or rayon
"Need concurrency for I/O"
↓ Use: async/await with tokio
"Need to share immutable data across threads"
↓ Use: Arc<T>
"Need to share mutable data across threads"
↓ Use: Arc<Mutex<T>> or Arc<RwLock<T>>
↓ Or: channels for message passing
"Need simple atomic operations"
↓ Use: AtomicBool, AtomicUsize, etc.
| Marker | Meaning | Example |
|--------|---------|---------|
| Send | Can transfer ownership between threads | Most types |
| Sync | Can share references between threads | Arc<T> |
| !Send | Must stay on one thread | Rc<T> |
| !Sync | No shared refs across threads | RefCell<T> |
| Pattern | Thread-Safe | Blocking | Use When |
|---------|-------------|----------|----------|
| std::thread | Yes | Yes | CPU-bound parallelism |
| async/await | Yes | No | I/O-bound concurrency |
| Mutex<T> | Yes | Yes | Shared mutable state |
| RwLock<T> | Yes | Yes | Read-heavy shared state |
| mpsc::channel | Yes | Optional | Message passing |
| Arc<Mutex<T>> | Yes | Yes | Shared mutable across threads |
What type of work?
├─ CPU-bound → std::thread or rayon
├─ I/O-bound → async/await
└─ Mixed → hybrid (spawn_blocking)
Need to share data?
├─ No → message passing (channels)
├─ Immutable → Arc<T>
└─ Mutable →
├─ Read-heavy → Arc<RwLock<T>>
└─ Write-heavy → Arc<Mutex<T>>
└─ Simple counter → AtomicUsize
Async context?
├─ Type is Send → tokio::spawn
├─ Type is !Send → spawn_local
└─ Blocking code → spawn_blocking
| Error | Cause | Fix |
|-------|-------|-----|
| E0277 Send not satisfied | Non-Send in async | Use Arc or spawn_local |
| E0277 Sync not satisfied | Non-Sync shared | Wrap with Mutex |
| Deadlock | Lock ordering | Consistent lock order |
| future is not Send | Non-Send across await | Drop before await |
| MutexGuard across await | Guard held during suspend | Scope guard properly |
| Anti-Pattern | Why Bad | Better | |--------------|---------|--------| | Arc<Mutex<T>> everywhere | Contention, complexity | Message passing | | thread::sleep in async | Blocks executor | tokio::time::sleep | | Holding locks across await | Blocks other tasks | Scope locks tightly | | Ignoring deadlock risk | Hard to debug | Lock ordering, try_lock |
// Bad: guard held across await
let guard = mutex.lock().await;
do_async().await; // guard still held!
// Good: scope the lock
{
let guard = mutex.lock().await;
// use guard
} // guard dropped
do_async().await;
// Rc is !Send, can't cross await in spawned task
// Option 1: use Arc instead
// Option 2: use spawn_local (single-thread runtime)
// Option 3: ensure Rc is dropped before .await
| When | See | |------|-----| | Smart pointer choice | m02-resource | | Interior mutability | m03-mutability | | Performance tuning | m10-performance | | Domain concurrency needs | domain-* |
development
CRITICAL: Use for unsafe Rust code review and FFI. Triggers on: unsafe, raw pointer, FFI, extern, transmute, *mut, *const, union, #[repr(C)], libc, std::ffi, MaybeUninit, NonNull, SAFETY comment, soundness, undefined behavior, UB, safe wrapper, memory layout, bindgen, cbindgen, CString, CStr
development
Explore Rust trait implementations using LSP. Triggers on: /trait-impl, find implementations, who implements
development
Analyze Rust project structure using LSP symbols. Triggers on: /symbols, project structure, list structs, list traits, list functions
development
Use when creating skills for Rust crates or std library documentation. Keywords: create rust skill, create crate skill, create std skill, skill for tokio, skill for serde, skill for axum, generate rust skill, from docs create skill