Un atelier Rust · Édition d'ApprentissageA Rust Workshop · Learning Edition

Send, Sync & Arc<Mutex<T>> Send, Sync & Arc<Mutex<T>>

Arc pour partager la possession entre threads, Mutex pour rétablir l'exclusivité — ni l'un ni l'autre ne suffit seul. Et le rappel honnête : Rust empêche le data race, pas le deadlock. Arc to share ownership across threads, Mutex to restore exclusivity — neither alone is enough. And the honest reminder: Rust prevents the data race, not the deadlock.

AudienceAudience
Dev maîtrisant possession, Rc/Arc et les threads (Vol 1, Vol 6, Vol 7 №1) Dev fluent in ownership, Rc/Arc and threads (Vol 1, Vol 6, Vol 7 №1)
Format
Self-paced
ChapitresChapters
5
Date
Juin 2026 Jun 2026
≈ 19 min ●●●● ConcurrenceSendMutex

Chapitre 1 en accès libre — la suite (ch. 2 à 5) est réservée. Chapter 1 free to read — the rest (ch. 2–5) is members-only.

01CadrageFraming3 min

Deux traits qu'on n'écrit jamais décident ce qui a le droit de traverser un thread.Two traits you never write decide what is allowed to cross a thread.

Le numéro précédent a laissé une porte fermée. move donne une donnée à un seul thread ; thread::scope la prête à plusieurs, mais en lecture seule — parce que « aliasing XOR mutation » interdit que deux threads la tiennent pendant que l'un écrit. Reste le cas le plus courant en pratique : plusieurs threads qui veulent muter la même donnée. Un compteur, un cache, un état partagé. Avant d'y arriver, il faut nommer la mécanique invisible qui gouvernait déjà le refus du №1 : Send et Sync. Ce sont deux traits marqueurs, auto-dérivés par le compilateur, qui répondent à deux questions précises — cette donnée peut-elle partir dans un autre thread (Send) ? une référence vers elle peut-elle être partagée entre threads (Sync) ? Toute la sûreté de la concurrence en Rust repose sur ces deux réponses, calculées à la compilation, sans qu'on écrive une ligne.The previous issue left one door shut. move gives data to a single thread; thread::scope lends it to several, but read-only — because 'aliasing XOR mutation' forbids two threads holding it while one writes. That leaves the most common case in practice: several threads wanting to mutate the same data. A counter, a cache, a shared state. Before getting there, we must name the invisible machinery that already governed the №1 refusal: Send and Sync. These are two marker traits, auto-derived by the compiler, answering two precise questions — can this data leave for another thread (Send)? can a reference to it be shared between threads (Sync)? All of Rust's concurrency safety rests on these two answers, computed at compile time, without writing a line.

Send et Sync — qui peut traverser, qui peut être partagéSend and Sync — who can cross, who can be shared
typetype
Send
Sync
pourquoiwhy
i32, String, Vec<T>
le cas normalthe normal case
Rc<T>
compteur non atomiquenon-atomic counter
Arc<T>
compteur atomique (Vol 6)atomic counter (Vol 6)
RefCell<T>
borrow check non synchroniséunsynchronized borrow check
Mutex<T>
verrou → exclusivité sûrelock → safe exclusivity
L'autre moitié de la signature de spawnThe other half of spawn's signature
// la signature de thread::spawn impose DEUX bornes — pas une
pub fn spawn<F, T>(f: F) -> JoinHandle<T>
where
    F: FnOnce() -> T + Send + 'static,    // 'static (vu au №1) ET Send (ce numéro)
    T: Send + 'static;

// 'static  → « ne dépend d'aucun emprunt à durée limitée »   (le QUAND)
// Send     → « la possession peut PARTIR vers un autre thread » (le QUOI)
// le refus du №1 portait sur la durée de vie. voici l'autre moitié : ce qui a
// le DROIT de traverser. un Rc, par exemple, ne l'a pas — et le compilateur le sait.

Au №1, on a buté sur 'static : quand la donnée peut vivre. Mais spawn exige une seconde garantie — Send : quoi peut quitter le thread courant. Les deux sont des traits marqueurs : ils ne portent aucune méthode, ils étiquettent simplement un type comme sûr pour une opération. Et ils sont auto-dérivés : un type est Send (resp. Sync) si tous ses champs le sont. Tu n'écris presque jamais impl Send — le compilateur le déduit, et c'est ce calcul silencieux qui rend le data race inexprimable.In №1, we hit 'static: when the data may live. But spawn demands a second guarantee — Send: what may leave the current thread. Both are marker traits: they carry no method, they simply tag a type as safe for an operation. And they're auto-derived: a type is Send (resp. Sync) if all its fields are. You almost never write impl Send — the compiler deduces it, and that silent computation is what makes a data race inexpressible.

Le réflexe du numéroThe issue's reflex

« Pour partager et muter entre threads, il faut deux outils, pas un : qui partage la possession, qui rétablit l'exclusivité ? » Arc répond au premier, Mutex au second — et ils vont ensemble parce que ni l'un ni l'autre ne suffit. Arc seul partage en lecture ; Mutex seul ne se partage pas. La concurrence sûre, c'est l'assemblage exact des deux.'To share and mutate across threads, you need two tools, not one: which shares ownership, which restores exclusivity?' Arc answers the first, Mutex the second — and they go together because neither alone suffices. Arc alone shares read-only; Mutex alone can't be shared. Safe concurrency is the exact assembly of both.

Send et Sync, en une phrase chacunSend and Sync, one sentence each

Send : la possession d'une valeur peut être transférée vers un autre thread (la valeur « part »). Sync : une référence partagée &T peut être utilisée depuis plusieurs threads à la fois — ce qui revient exactement à dire « &T est Send ». Presque tout est Send et Sync. Les exceptions sont instructives : Rc (compteur non atomique), Cell et RefCell (mutabilité intérieure non synchronisée), les pointeurs bruts. Chacune est un type que Rust refuse de laisser traverser, précisément parce qu'il provoquerait une course.Send: ownership of a value can be transferred to another thread (the value 'leaves'). Sync: a shared reference &T can be used from several threads at once — which is exactly to say '&T is Send'. Almost everything is Send and Sync. The exceptions are instructive: Rc (non-atomic counter), Cell and RefCell (unsynchronized interior mutability), raw pointers. Each is a type Rust refuses to let cross, precisely because it would cause a race.

🔒

La suite est réservée The rest is members-only

Le premier numéro est libre. Débloque tout The Rust Loop — tous les volumes, à vie — pour 5 €, paiement unique. The first issue is free. Unlock all of The Rust Loop — every volume, forever — for €5, one-time.

Retour au kiosqueBack to newsstand