M07 Concurrency

by actionbook5c40d3ad7851No license1.5K starsListed Oct 8, 2026Updated Oct 8, 2026Repository updated 6 weeks ago

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, 并发, 线程, 异步, 死锁

Instructions onlySoftware Development
AI-generated overview

Guides Rust concurrency and async design decisions, from Send/Sync errors to choosing threads, channels, or async runtimes.

What it does
This skill is a reference for reasoning about Rust concurrency and async programming. It maps common compiler errors such as E0277 Send/Sync and non-Send futures to underlying design questions, and provides decision tables for choosing between threads, async/await, channels, Arc, Mutex, RwLock, and atomics. It also lists anti-patterns and async-specific pitfalls like holding a MutexGuard across an await.
When to use it
Use it when working through Rust concurrency or async problems, especially Send/Sync trait errors, deadlocks, race conditions, or decisions about threads versus async. It is also useful when choosing a sharing model for data accessed across threads or tasks.
Requirements
No scripts or runtime dependencies; it is an instructions-only reference document. It assumes familiarity with Rust concurrency concepts and may reference related skills such as domain-web, domain-cli, m09-domain, and m10-performance.

Concurrency

Layer 1: Language Mechanics

Core Question

Is this CPU-bound or I/O-bound, and what's the sharing model?

Before choosing concurrency primitives:

  • What's the workload type?
  • What data needs to be shared?
  • What's the thread safety requirement?

Error → Design Question

ErrorDon't Just SayAsk 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?

Thinking Prompt

Before adding concurrency:

  1. What's the workload?

    • CPU-bound → threads (std::thread, rayon)
    • I/O-bound → async (tokio, async-std)
    • Mixed → hybrid approach
  2. What's the sharing model?

    • No sharing → message passing (channels)
    • Immutable sharing → Arc<T>
    • Mutable sharing → Arc<Mutex<T>> or Arc<RwLock<T>>
  3. What are the Send/Sync requirements?

    • Cross-thread ownership → Send
    • Cross-thread references → Sync
    • Single-thread async → spawn_local

Trace Up ↑ (MANDATORY)

CRITICAL: Don't just fix the error. Trace UP to find domain constraints.

Domain Detection Table

Context KeywordsLoad Domain SkillKey Constraint
Web API, HTTP, axum, actix, handlerdomain-webHandlers run on any thread
交易, 支付, trading, paymentdomain-fintechAudit + thread safety
gRPC, kubernetes, microservicedomain-cloud-nativeDistributed tracing
CLI, terminal, clapdomain-cliUsually single-thread OK

Example: Web API + Rc Error

"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>>

Generic Trace

"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?)
SituationTrace ToQuestion
Send/Sync in Webdomain-webWhat's the state management pattern?
Send/Sync in CLIdomain-cliIs multi-thread really needed?
Mutex vs channelsm09-domainShared state or message passing?
Async vs threadsm10-performanceWhat's the workload profile?

Trace Down ↓

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.

Send/Sync Markers

MarkerMeaningExample
SendCan transfer ownership between threadsMost types
SyncCan share references between threadsArc<T>
!SendMust stay on one threadRc<T>
!SyncNo shared refs across threadsRefCell<T>

Quick Reference

PatternThread-SafeBlockingUse When
std::threadYesYesCPU-bound parallelism
async/awaitYesNoI/O-bound concurrency
Mutex<T>YesYesShared mutable state
RwLock<T>YesYesRead-heavy shared state
mpsc::channelYesOptionalMessage passing
Arc<Mutex<T>>YesYesShared mutable across threads

Decision Flowchart

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

Common Errors

ErrorCauseFix
E0277 Send not satisfiedNon-Send in asyncUse Arc or spawn_local
E0277 Sync not satisfiedNon-Sync sharedWrap with Mutex
DeadlockLock orderingConsistent lock order
future is not SendNon-Send across awaitDrop before await
MutexGuard across awaitGuard held during suspendScope guard properly

Anti-Patterns

Anti-PatternWhy BadBetter
Arc<Mutex<T>> everywhereContention, complexityMessage passing
thread::sleep in asyncBlocks executortokio::time::sleep
Holding locks across awaitBlocks other tasksScope locks tightly
Ignoring deadlock riskHard to debugLock ordering, try_lock

Async-Specific Patterns

Avoid MutexGuard Across Await

rust
// Bad: guard held across awaitlet guard = mutex.lock().await;do_async().await;  // guard still held!
// Good: scope the lock{    let guard = mutex.lock().await;    // use guard}  // guard droppeddo_async().await;

Non-Send Types in Async

rust
// 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

Related Skills

WhenSee
Smart pointer choicem02-resource
Interior mutabilitym03-mutability
Performance tuningm10-performance
Domain concurrency needsdomain-*

Source and attribution

Source:actionbook/rust-skillsinskills/m07-concurrencyat commit5c40d3a

License: No license

Content belongs to its original authors. SourceWeft indexes it from a public repository.

Report or request removal