std/sync/mod.rs
1//! Useful synchronization primitives.
2//!
3//! ## The need for synchronization
4//!
5//! Conceptually, a Rust program is a series of operations which will
6//! be executed on a computer. The timeline of events happening in the
7//! program is consistent with the order of the operations in the code.
8//!
9//! Consider the following code, operating on some global static variables:
10//!
11//! ```rust
12//! // FIXME(static_mut_refs): Do not allow `static_mut_refs` lint
13//! #![allow(static_mut_refs)]
14//!
15//! static mut A: u32 = 0;
16//! static mut B: u32 = 0;
17//! static mut C: u32 = 0;
18//!
19//! fn main() {
20//! unsafe {
21//! A = 3;
22//! B = 4;
23//! A = A + B;
24//! C = B;
25//! println!("{A} {B} {C}");
26//! C = A;
27//! }
28//! }
29//! ```
30//!
31//! It appears as if some variables stored in memory are changed, an addition
32//! is performed, result is stored in `A` and the variable `C` is
33//! modified twice.
34//!
35//! When only a single thread is involved, the results are as expected:
36//! the line `7 4 4` gets printed.
37//!
38//! As for what happens behind the scenes, when optimizations are enabled the
39//! final generated machine code might look very different from the code:
40//!
41//! - The first store to `C` might be moved before the store to `A` or `B`,
42//! _as if_ we had written `C = 4; A = 3; B = 4`.
43//!
44//! - Assignment of `A + B` to `A` might be removed, since the sum can be stored
45//! in a temporary location until it gets printed, with the global variable
46//! never getting updated.
47//!
48//! - The final result could be determined just by looking at the code
49//! at compile time, so [constant folding] might turn the whole
50//! block into a simple `println!("7 4 4")`.
51//!
52//! The compiler is allowed to perform any combination of these
53//! optimizations, as long as the final optimized code, when executed,
54//! produces the same results as the one without optimizations.
55//!
56//! Due to the [concurrency] involved in modern computers, assumptions
57//! about the program's execution order are often wrong. Access to
58//! global variables can lead to nondeterministic results, **even if**
59//! compiler optimizations are disabled, and it is **still possible**
60//! to introduce synchronization bugs.
61//!
62//! Note that thanks to Rust's safety guarantees, accessing global (static)
63//! variables requires `unsafe` code, assuming we don't use any of the
64//! synchronization primitives in this module.
65//!
66//! [constant folding]: https://en.wikipedia.org/wiki/Constant_folding
67//! [concurrency]: https://en.wikipedia.org/wiki/Concurrency_(computer_science)
68//!
69//! ## Out-of-order execution
70//!
71//! Instructions can execute in a different order from the one we define, due to
72//! various reasons:
73//!
74//! - The **compiler** reordering instructions: If the compiler can issue an
75//! instruction at an earlier point, it will try to do so. For example, it
76//! might hoist memory loads at the top of a code block, so that the CPU can
77//! start [prefetching] the values from memory.
78//!
79//! In single-threaded scenarios, this can cause issues when writing
80//! signal handlers or certain kinds of low-level code.
81//! Use [compiler fences] to prevent this reordering.
82//!
83//! - A **single processor** executing instructions [out-of-order]:
84//! Modern CPUs are capable of [superscalar] execution,
85//! i.e., multiple instructions might be executing at the same time,
86//! even though the machine code describes a sequential process.
87//!
88//! This kind of reordering is handled transparently by the CPU.
89//!
90//! - A **multiprocessor** system executing multiple hardware threads
91//! at the same time: In multi-threaded scenarios, you can use two
92//! kinds of primitives to deal with synchronization:
93//! - [memory fences] to ensure memory accesses are made visible to
94//! other CPUs in the right order.
95//! - [atomic operations] to ensure simultaneous access to the same
96//! memory location doesn't lead to undefined behavior.
97//!
98//! [prefetching]: https://en.wikipedia.org/wiki/Cache_prefetching
99//! [compiler fences]: crate::sync::atomic::compiler_fence
100//! [out-of-order]: https://en.wikipedia.org/wiki/Out-of-order_execution
101//! [superscalar]: https://en.wikipedia.org/wiki/Superscalar_processor
102//! [memory fences]: crate::sync::atomic::fence
103//! [atomic operations]: crate::sync::atomic
104//!
105//! ## Higher-level synchronization objects
106//!
107//! Most of the low-level synchronization primitives are quite error-prone and
108//! inconvenient to use, which is why the standard library also exposes some
109//! higher-level synchronization objects.
110//!
111//! These abstractions can be built out of lower-level primitives.
112//! For efficiency, the sync objects in the standard library are usually
113//! implemented with help from the operating system's kernel, which is
114//! able to reschedule the threads while they are blocked on acquiring
115//! a lock.
116//!
117//! The following is an overview of the available synchronization
118//! objects:
119//!
120//! - [`Arc`]: Atomically Reference-Counted pointer, which can be used
121//! in multithreaded environments to prolong the lifetime of some
122//! data until all the threads have finished using it.
123//!
124//! - [`Barrier`]: Ensures multiple threads will wait for each other
125//! to reach a point in the program, before continuing execution all
126//! together.
127//!
128//! - [`Condvar`]: Condition Variable, providing the ability to block
129//! a thread while waiting for an event to occur.
130//!
131//! - [`mpsc`]: Multi-producer, single-consumer queues, used for
132//! message-based communication. Can provide a lightweight
133//! inter-thread synchronisation mechanism, at the cost of some
134//! extra memory.
135//!
136//! - [`mpmc`]: Multi-producer, multi-consumer queues, used for
137//! message-based communication. Can provide a lightweight
138//! inter-thread synchronisation mechanism, at the cost of some
139//! extra memory.
140//!
141//! - [`Mutex`]: Mutual Exclusion mechanism, which ensures that at
142//! most one thread at a time is able to access some data.
143//!
144//! - [`Once`]: Used for a thread-safe, one-time global initialization routine.
145//! Mostly useful for implementing other types like `OnceLock`.
146//!
147//! - [`OnceLock`]: Used for thread-safe, one-time initialization of a
148//! variable, with potentially different initializers based on the caller.
149//!
150//! - [`LazyLock`]: Used for thread-safe, one-time initialization of a
151//! variable, using one nullary initializer function provided at creation.
152//!
153//! - [`RwLock`]: Provides a mutual exclusion mechanism which allows
154//! multiple readers at the same time, while allowing only one
155//! writer at a time. In some cases, this can be more efficient than
156//! a mutex.
157//!
158//! [`Arc`]: crate::sync::Arc
159//! [`Barrier`]: crate::sync::Barrier
160//! [`Condvar`]: crate::sync::Condvar
161//! [`mpmc`]: crate::sync::mpmc
162//! [`mpsc`]: crate::sync::mpsc
163//! [`Mutex`]: crate::sync::Mutex
164//! [`Once`]: crate::sync::Once
165//! [`OnceLock`]: crate::sync::OnceLock
166//! [`RwLock`]: crate::sync::RwLock
167
168#![stable(feature = "rust1", since = "1.0.0")]
169
170// No formatting: this file is just re-exports, and their order is worth preserving.
171#![cfg_attr(rustfmt, rustfmt::skip)]
172
173// These come from `core` & `alloc` and only in one flavor: no poisoning.
174#[unstable(feature = "exclusive_wrapper", issue = "98407")]
175pub use core::sync::Exclusive;
176#[stable(feature = "rust1", since = "1.0.0")]
177pub use core::sync::atomic;
178
179#[stable(feature = "rust1", since = "1.0.0")]
180pub use alloc_crate::sync::{Arc, Weak};
181
182// FIXME(sync_nonpoison,sync_poison_mod): remove all `#[doc(inline)]` once the modules are stabilized.
183
184// These exist only in one flavor: no poisoning.
185#[stable(feature = "rust1", since = "1.0.0")]
186pub use self::barrier::{Barrier, BarrierWaitResult};
187#[stable(feature = "lazy_cell", since = "1.80.0")]
188pub use self::lazy_lock::LazyLock;
189#[stable(feature = "once_cell", since = "1.70.0")]
190pub use self::once_lock::OnceLock;
191#[unstable(feature = "reentrant_lock", issue = "121440")]
192pub use self::reentrant_lock::{ReentrantLock, ReentrantLockGuard};
193
194// These make sense and exist only with poisoning.
195#[stable(feature = "rust1", since = "1.0.0")]
196#[doc(inline)]
197pub use self::poison::{LockResult, PoisonError};
198
199// These (should) exist in both flavors: with and without poisoning.
200// FIXME(sync_nonpoison): implement nonpoison versions:
201// * Mutex (nonpoison_mutex)
202// * Condvar (nonpoison_condvar)
203// * Once (nonpoison_once)
204// * RwLock (nonpoison_rwlock)
205// The historical default is the version with poisoning.
206#[stable(feature = "rust1", since = "1.0.0")]
207#[doc(inline)]
208pub use self::poison::{
209 Mutex, MutexGuard, TryLockError, TryLockResult,
210 Condvar, WaitTimeoutResult,
211 Once, OnceState,
212 RwLock, RwLockReadGuard, RwLockWriteGuard,
213};
214#[stable(feature = "rust1", since = "1.0.0")]
215#[doc(inline)]
216#[expect(deprecated)]
217pub use self::poison::ONCE_INIT;
218#[unstable(feature = "mapped_lock_guards", issue = "117108")]
219#[doc(inline)]
220pub use self::poison::{MappedMutexGuard, MappedRwLockReadGuard, MappedRwLockWriteGuard};
221
222#[unstable(feature = "mpmc_channel", issue = "126840")]
223pub mod mpmc;
224pub mod mpsc;
225
226#[unstable(feature = "sync_poison_mod", issue = "134646")]
227pub mod poison;
228
229mod barrier;
230mod lazy_lock;
231mod once_lock;
232mod reentrant_lock;