Rust Send и Sync
- title
- Rust Send и Sync
- type
- concept
- summary
- Два auto-trait'а потокобезопасности в Rust: Send для перемещения между потоками, Sync для разделяемых ссылок, с правилом &T: Send ⇔ T: Sync
- tags
- rust, type-system, concurrency
- sources
- verrchu-sync-bound
- created
- 2026-05-10
- updated
- 2026-07-29
- lang
- ru
- translation_of
- rust-send-sync
- source_updated
- 2026-07-29
- translated
- 2026-09-01
- translator
- lllm/antigravity/gemini-3.7-flash-medium
Send и Sync - два auto-trait'а потокобезопасности в Rust. Они выводятся автоматически (структура получает их тогда и только тогда, когда ими обладают все её поля) и определяют, что borrow checker разрешает делать между потоками:
T: Send- значения типаTможно перемещать в другой поток.Rc<T>не являетсяSend(гонка при изменении счётчика ссылок);Arc<T>являетсяSend, еслиT: Send + Sync.T: Sync-&Tможно разделять между потоками. Эквивалентно:T: Sync⇔&T: Send.Cell<T>не являетсяSync(внутренняя мутабельность без синхронизации); дляMutex<T>: Syncтребуется лишьT: Send.
Неочевидные правила, которые делают это критически важным на практике:
| Тип | Для Send требуется |
Для Sync требуется |
|---|---|---|
&T |
T: Sync |
T: Sync |
&mut T |
T: Send |
T: Sync |
Box<T> |
T: Send |
T: Sync |
Rc<T> |
никогда | никогда |
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 |
никогда |
Правило &T: Send ⇔ T: Sync часто оказывается неожиданным и служит причиной подводного камня в rust-async-trait-sync-bound - захват &self в Send-future неявно требует Self: Sync, даже когда в коде ничто явно об этом не просит.
Обходные пути, когда поле имеет тип !Sync, но требуется Send-future:
- Обернуть поле в
Mutex<T>- дляMutex<T>: Syncтребуется толькоT: Send - Использовать
&mut selfвместо&self- для&mut T: Sendнужен толькоT: Send - Сделать захваченное значение владеемым (переместить его в future) - выбор владения вместо заимствования снимает проблему
Для понимания логики дизайна языка (&mut как уникальность, а не мутабельность) канонической является статья Нико Мацакиса "Focusing on ownership". В safety-in-an-unsafe-world Send приводится как практический пример свойства безопасности, определённого библиотекой: смысл trait'а полностью заключён в комментарии к документации, unsafe impl служит реализацией гарантии, а ограничение F: Send у spawn обосновывает лежащий под ним вызов pthread_create.
См. также: rust-async-trait-sync-bound, message-passing-vs-shared-memory.