rust-async
SKILL.md
Concurrency & Async
Thread Safety
| Error | Cause | Fix |
|---|---|---|
Rc<T> cannot be sent between threads |
Rc is not Send |
Use Arc |
RefCell<T> is not Sync |
Not thread-safe | Use Mutex or RwLock |
Cannot mutate through Arc |
No interior mutability | Arc<Mutex<T>> or Arc<AtomicT> |
Deadlock Prevention
- Lock ordering: Always acquire multiple locks in the same order across all threads
- Self-deadlock: Never lock the same
std::Mutextwice (useparking_lot::ReentrantMutexif needed) - Scope locks tightly: Drop guards as soon as possible
- Atomics for primitives: Use
AtomicBool/AtomicUsizeinstead ofMutex<bool> - Choose memory order carefully:
Relaxed/Acquire/Release/SeqCst
Async Patterns
| Pattern | When to Use |
|---|---|
tokio::spawn |
Fire-and-forget concurrent tasks |
tokio::select! |
Race multiple futures, cancel losers |
mpsc channel |
Fan-in: many producers, one consumer |
oneshot channel |
Single request-response |
broadcast channel |
One producer, many consumers |
watch channel |
Latest-value state sharing |
JoinSet |
Manage group of spawned tasks |
CancellationToken |
Graceful shutdown signaling |
Critical Async Mistakes
Mutex Guard Across Await
// BAD: std::Mutex guard held across .await — blocks executor
async fn bad() {
let guard = mutex.lock().unwrap();
some_async_op().await; // guard held across await!
println!("{}", *guard);
}
// GOOD: scope the lock, copy what you need
async fn good() {
let value = {
let guard = mutex.lock().unwrap();
*guard // copy value
}; // guard dropped here
some_async_op().await;
println!("{}", value);
}
Blocking in Async Context
// BAD: blocking call in async context
async fn bad() {
std::thread::sleep(Duration::from_secs(1)); // blocks executor!
std::fs::read_to_string("file.txt").unwrap(); // blocks!
}
// GOOD: use async equivalents
async fn good() {
tokio::time::sleep(Duration::from_secs(1)).await;
tokio::fs::read_to_string("file.txt").await.unwrap();
}
// For CPU work: spawn_blocking
let result = tokio::task::spawn_blocking(|| heavy_computation()).await.unwrap();
Forgetting to Poll Futures
// BAD: future not polled — does nothing!
fn process() {
fetch_data(); // returns Future that's immediately dropped
}
// GOOD: await it
async fn process() {
let data = fetch_data().await;
}
Key Rule
// Sync for CPU-bound work, async for I/O-bound work
// Don't hold locks across await points
Channel Disconnection
// Iterate until all senders drop
for msg in rx {
handle(msg);
}
// Explicit matching for non-blocking
match rx.try_recv() {
Ok(msg) => handle(msg),
Err(TryRecvError::Empty) => continue,
Err(TryRecvError::Disconnected) => break,
}
Thread Panic Handling
let handle = std::thread::spawn(|| risky_operation());
match handle.join() {
Ok(result) => use_result(result),
Err(e) => eprintln!("Thread panicked: {:?}", e),
}
Graceful Shutdown Pattern
use tokio_util::sync::CancellationToken;
async fn run(token: CancellationToken) {
loop {
tokio::select! {
_ = token.cancelled() => {
tracing::info!("shutting down");
break;
}
msg = rx.recv() => {
if let Some(msg) = msg {
handle(msg).await;
}
}
}
}
}
Weekly Installs
3
Repository
peixotorms/odin…r-skillsGitHub Stars
3
First Seen
Feb 9, 2026
Security Audits
Installed on
opencode3
gemini-cli3
claude-code3
github-copilot3
codex3
kimi-cli3