]> git.proxmox.com Git - rustc.git/blame - src/doc/nomicon/src/send-and-sync.md
New upstream version 1.57.0+dfsg1
[rustc.git] / src / doc / nomicon / src / send-and-sync.md
CommitLineData
8bb4bdeb 1# Send and Sync
c1a9b12d
SL
2
3Not everything obeys inherited mutability, though. Some types allow you to
7cac9316 4have multiple aliases of a location in memory while mutating it. Unless these types use
2c00a5a8 5synchronization to manage this access, they are absolutely not thread-safe. Rust
e9174d1e 6captures this through the `Send` and `Sync` traits.
c1a9b12d
SL
7
8* A type is Send if it is safe to send it to another thread.
29967ef6 9* A type is Sync if it is safe to share between threads (T is Sync if and only if `&T` is Send).
c1a9b12d
SL
10
11Send and Sync are fundamental to Rust's concurrency story. As such, a
12substantial amount of special tooling exists to make them work right. First and
e9174d1e
SL
13foremost, they're [unsafe traits]. This means that they are unsafe to
14implement, and other unsafe code can assume that they are correctly
c1a9b12d
SL
15implemented. Since they're *marker traits* (they have no associated items like
16methods), correctly implemented simply means that they have the intrinsic
17properties an implementor should have. Incorrectly implementing Send or Sync can
b039eaaf 18cause Undefined Behavior.
c1a9b12d
SL
19
20Send and Sync are also automatically derived traits. This means that, unlike
21every other trait, if a type is composed entirely of Send or Sync types, then it
22is Send or Sync. Almost all primitives are Send and Sync, and as a consequence
23pretty much all types you'll ever interact with are Send and Sync.
24
25Major exceptions include:
26
27* raw pointers are neither Send nor Sync (because they have no safety guards).
28* `UnsafeCell` isn't Sync (and therefore `Cell` and `RefCell` aren't).
29* `Rc` isn't Send or Sync (because the refcount is shared and unsynchronized).
30
31`Rc` and `UnsafeCell` are very fundamentally not thread-safe: they enable
32unsynchronized shared mutable state. However raw pointers are, strictly
33speaking, marked as thread-unsafe as more of a *lint*. Doing anything useful
34with a raw pointer requires dereferencing it, which is already unsafe. In that
35sense, one could argue that it would be "fine" for them to be marked as thread
36safe.
37
2c00a5a8
XL
38However it's important that they aren't thread-safe to prevent types that
39contain them from being automatically marked as thread-safe. These types have
c1a9b12d 40non-trivial untracked ownership, and it's unlikely that their author was
2c00a5a8
XL
41necessarily thinking hard about thread safety. In the case of `Rc`, we have a nice
42example of a type that contains a `*mut` that is definitely not thread-safe.
c1a9b12d
SL
43
44Types that aren't automatically derived can simply implement them if desired:
45
46```rust
47struct MyBox(*mut u8);
48
49unsafe impl Send for MyBox {}
50unsafe impl Sync for MyBox {}
51```
52
53In the *incredibly rare* case that a type is inappropriately automatically
54derived to be Send or Sync, then one can also unimplement Send and Sync:
55
56```rust
ba9703b0 57#![feature(negative_impls)]
c1a9b12d
SL
58
59// I have some magic semantics for some synchronization primitive!
60struct SpecialThreadToken(u8);
61
62impl !Send for SpecialThreadToken {}
63impl !Sync for SpecialThreadToken {}
64```
65
66Note that *in and of itself* it is impossible to incorrectly derive Send and
67Sync. Only types that are ascribed special meaning by other unsafe code can
29967ef6 68possibly cause trouble by being incorrectly Send or Sync.
c1a9b12d
SL
69
70Most uses of raw pointers should be encapsulated behind a sufficient abstraction
71that Send and Sync can be derived. For instance all of Rust's standard
72collections are Send and Sync (when they contain Send and Sync types) in spite
73of their pervasive use of raw pointers to manage allocations and complex ownership.
74Similarly, most iterators into these collections are Send and Sync because they
75largely behave like an `&` or `&mut` into the collection.
76
cdc7bbd5
XL
77## Example
78
79[`Box`][box-doc] is implemented as it's own special intrinsic type by the
80compiler for [various reasons][box-is-special], but we can implement something
81with similar-ish behavior ourselves to see an example of when it is sound to
82implement Send and Sync. Let's call it a `Carton`.
83
84We start by writing code to take a value allocated on the stack and transfer it
85to the heap.
86
87```rust
88# pub mod libc {
89# pub use ::std::os::raw::{c_int, c_void};
90# #[allow(non_camel_case_types)]
91# pub type size_t = usize;
92# extern "C" { pub fn posix_memalign(memptr: *mut *mut c_void, align: size_t, size: size_t) -> c_int; }
93# }
94use std::{
95 mem::{align_of, size_of},
96 ptr,
97};
98
99struct Carton<T>(ptr::NonNull<T>);
100
101impl<T> Carton<T> {
102 pub fn new(value: T) -> Self {
103 // Allocate enough memory on the heap to store one T.
104 assert_ne!(size_of::<T>(), 0, "Zero-sized types are out of the scope of this example");
c295e0f8 105 let mut memptr: *mut T = ptr::null_mut();
cdc7bbd5
XL
106 unsafe {
107 let ret = libc::posix_memalign(
108 (&mut memptr).cast(),
109 align_of::<T>(),
110 size_of::<T>()
111 );
112 assert_eq!(ret, 0, "Failed to allocate or invalid alignment");
113 };
114
115 // NonNull is just a wrapper that enforces that the pointer isn't null.
c295e0f8 116 let ptr = {
cdc7bbd5
XL
117 // Safety: memptr is dereferenceable because we created it from a
118 // reference and have exclusive access.
c295e0f8 119 ptr::NonNull::new(memptr)
cdc7bbd5
XL
120 .expect("Guaranteed non-null if posix_memalign returns 0")
121 };
122
123 // Move value from the stack to the location we allocated on the heap.
124 unsafe {
125 // Safety: If non-null, posix_memalign gives us a ptr that is valid
126 // for writes and properly aligned.
127 ptr.as_ptr().write(value);
128 }
129
130 Self(ptr)
131 }
132}
133```
134
135This isn't very useful, because once our users give us a value they have no way
136to access it. [`Box`][box-doc] implements [`Deref`][deref-doc] and
137[`DerefMut`][deref-mut-doc] so that you can access the inner value. Let's do
138that.
139
140```rust
141use std::ops::{Deref, DerefMut};
142
143# struct Carton<T>(std::ptr::NonNull<T>);
144#
145impl<T> Deref for Carton<T> {
146 type Target = T;
147
148 fn deref(&self) -> &Self::Target {
149 unsafe {
150 // Safety: The pointer is aligned, initialized, and dereferenceable
151 // by the logic in [`Self::new`]. We require writers to borrow the
152 // Carton, and the lifetime of the return value is elided to the
153 // lifetime of the input. This means the borrow checker will
154 // enforce that no one can mutate the contents of the Carton until
155 // the reference returned is dropped.
156 self.0.as_ref()
157 }
158 }
159}
160
161impl<T> DerefMut for Carton<T> {
162 fn deref_mut(&mut self) -> &mut Self::Target {
163 unsafe {
164 // Safety: The pointer is aligned, initialized, and dereferenceable
165 // by the logic in [`Self::new`]. We require writers to mutably
166 // borrow the Carton, and the lifetime of the return value is
167 // elided to the lifetime of the input. This means the borrow
168 // checker will enforce that no one else can access the contents
169 // of the Carton until the mutable reference returned is dropped.
170 self.0.as_mut()
171 }
172 }
173}
174```
175
176Finally, let's think about whether our `Carton` is Send and Sync. Something can
177safely be Send unless it shares mutable state with something else without
178enforcing exclusive access to it. Each `Carton` has a unique pointer, so
179we're good.
180
181```rust
182# struct Carton<T>(std::ptr::NonNull<T>);
183// Safety: No one besides us has the raw pointer, so we can safely transfer the
184// Carton to another thread if T can be safely transferred.
185unsafe impl<T> Send for Carton<T> where T: Send {}
186```
187
188What about Sync? For `Carton` to be Sync we have to enforce that you can't
189write to something stored in a `&Carton` while that same something could be read
190or written to from another `&Carton`. Since you need an `&mut Carton` to
191write to the pointer, and the borrow checker enforces that mutable
192references must be exclusive, there are no soundness issues making `Carton`
193sync either.
194
195```rust
196# struct Carton<T>(std::ptr::NonNull<T>);
197// Safety: Since there exists a public way to go from a `&Carton<T>` to a `&T`
198// in an unsynchronized fashion (such as `Deref`), then `Carton<T>` can't be
199// `Sync` if `T` isn't.
200// Conversely, `Carton` itself does not use any interior mutability whatsoever:
201// all the mutations are performed through an exclusive reference (`&mut`). This
202// means it suffices that `T` be `Sync` for `Carton<T>` to be `Sync`:
203unsafe impl<T> Sync for Carton<T> where T: Sync {}
204```
205
206When we assert our type is Send and Sync we usually need to enforce that every
207contained type is Send and Sync. When writing custom types that behave like
208standard library types we can assert that we have the same requirements.
209For example, the following code asserts that a Carton is Send if the same
210sort of Box would be Send, which in this case is the same as saying T is Send.
211
212```rust
213# struct Carton<T>(std::ptr::NonNull<T>);
214unsafe impl<T> Send for Carton<T> where Box<T>: Send {}
215```
216
217Right now `Carton<T>` has a memory leak, as it never frees the memory it allocates.
218Once we fix that we have a new requirement we have to ensure we meet to be Send:
219we need to know `free` can be called on a pointer that was yielded by an
220allocation done on another thread. We can check this is true in the docs for
221[`libc::free`][libc-free-docs].
222
223```rust
224# struct Carton<T>(std::ptr::NonNull<T>);
225# mod libc {
226# pub use ::std::os::raw::c_void;
227# extern "C" { pub fn free(p: *mut c_void); }
228# }
229impl<T> Drop for Carton<T> {
230 fn drop(&mut self) {
231 unsafe {
232 libc::free(self.0.as_ptr().cast());
233 }
234 }
235}
236```
237
238A nice example where this does not happen is with a MutexGuard: notice how
239[it is not Send][mutex-guard-not-send-docs-rs]. The implementation of MutexGuard
240[uses libraries][mutex-guard-not-send-comment] that require you to ensure you
241don't try to free a lock that you acquired in a different thread. If you were
242able to Send a MutexGuard to another thread the destructor would run in the
243thread you sent it to, violating the requirement. MutexGuard can still be Sync
244because all you can send to another thread is an `&MutexGuard` and dropping a
245reference does nothing.
246
c1a9b12d
SL
247TODO: better explain what can or can't be Send or Sync. Sufficient to appeal
248only to data races?
249
250[unsafe traits]: safe-unsafe-meaning.html
cdc7bbd5
XL
251[box-doc]: https://doc.rust-lang.org/std/boxed/struct.Box.html
252[box-is-special]: https://manishearth.github.io/blog/2017/01/10/rust-tidbits-box-is-special/
253[deref-doc]: https://doc.rust-lang.org/core/ops/trait.Deref.html
254[deref-mut-doc]: https://doc.rust-lang.org/core/ops/trait.DerefMut.html
255[mutex-guard-not-send-docs-rs]: https://doc.rust-lang.org/std/sync/struct.MutexGuard.html#impl-Send
256[mutex-guard-not-send-comment]: https://github.com/rust-lang/rust/issues/23465#issuecomment-82730326
257[libc-free-docs]: https://linux.die.net/man/3/free