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