rust-concurrency-synclisted
Install: claude install-skill takurot/rust-skills-comprehensive
# Rust Threads & Shared State
`rust-patterns` has a short `Arc<Mutex<T>>`/channels section for the default idiom. This
skill is for when threading **is** the task: a `Send`/`Sync` compile error to fix, a channel
type to choose, or a hang/deadlock to diagnose. For `async`/`await` concurrency instead of OS
threads, see `rust-async`.
## Threads: spawned vs. scoped
`thread::spawn` closures must be `'static` — they **cannot borrow** from the spawning
function's stack, because the spawned thread might outlive it:
```rust
// Does not compile: closure would borrow `s`, but the thread could outlive `foo`
fn foo() {
let s = String::from("Hello");
thread::spawn(|| dbg!(s.len()));
}
```
Two fixes:
- **Own the data**: `move ||` the value into the closure, or clone/wrap it (`Arc`) if it's
needed elsewhere too.
- **`thread::scope`**: guarantees every thread spawned inside the scope closure is joined
before the scope returns, so borrows from the enclosing stack frame are sound:
```rust
thread::scope(|scope| {
scope.spawn(|| dbg!(s.len())); // borrowing `s` is fine here
});
```
Normal borrowing rules still apply inside a scope: one thread may hold `&mut`, or any number
may hold `&`, never both at once.
**`thread::spawn` doesn't keep `main` alive** — if `main` returns first, unjoined spawned
threads are simply cut off (not even guaranteed to finish). Capture the `JoinHandle` and call
`.join()` if you need the thread's work to complete, or its return value:
```rust
let