Rust Send and Sync

title
Rust Send and Sync
type
concept
summary
The two auto-traits that govern thread safety in Rust; Send for cross-thread move, Sync for cross-thread shared reference, with &T: Send ⇔ T: Sync
tags
rust, type-system, concurrency
created
2026-05-10
updated
2026-07-29

Send and Sync are Rust's two auto-traits for thread safety. They're auto-derived (every struct gets them iff all fields have them), and they govern what the borrow checker permits across threads:

  • T: Send β€” values of T can be moved to another thread. Rc<T> is not Send (refcount race); Arc<T> is Send if T: Send + Sync.
  • T: Sync β€” &T can be shared across threads. Equivalently, T: Sync ⇔ &T: Send. Cell<T> is not Sync (interior mutation without synchronization); Mutex<T>: Sync only requires T: Send.

The non-obvious rules that make this load-bearing in practice:

Type Send requires Sync requires
&T T: Sync T: Sync
&mut T T: Send T: Sync
Box<T> T: Send T: Sync
Rc<T> never never
Arc<T> T: Send + Sync T: Send + Sync
Mutex<T> T: Send T: Send
RwLock<T> T: Send T: Send + Sync
Cell<T> T: Send never

The &T: Send ⇔ T: Sync rule is the one that surprises people, and it's the source of the rust-async-trait-sync-bound gotcha β€” capturing &self in a Send future silently demands Self: Sync, even when nothing in the code obviously asks for it.

Workarounds when you have a !Sync field but need a Send future:

  • Wrap the field in Mutex<T> β€” Mutex<T>: Sync only requires T: Send
  • Use &mut self instead of &self β€” &mut T: Send only needs T: Send
  • Make the captured value owned (move into the future) β€” owned-vs-borrowed avoids the issue

For the language-design rationale (&mut as uniqueness, not mutation), Niko Matsakis's "Focusing on ownership" is canonical. safety-in-an-unsafe-world uses Send as its worked example of a library-defined safety property: the trait's meaning lives entirely in its doc comment, unsafe impl is the enforcement, and the F: Send bound on spawn is what justifies the pthread_create call underneath.

Cross-references: rust-async-trait-sync-bound, message-passing-vs-shared-memory.

Sub-pages