1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
//! 有用的同步原语。
//!
//! ## 需要同步
//!
//! 从概念上讲,Rust 程序是将在计算机上执行的一系列操作。程序中发生的事件的时间线与代码中操作的顺序一致。
//!
//! 考虑下面的代码,对某些静态变量进行操作:
//!
//! ```rust
//! static mut A: u32 = 0;
//! static mut B: u32 = 0;
//! static mut C: u32 = 0;
//!
//! fn main() {
//!     unsafe {
//!         A = 3;
//!         B = 4;
//!         A = A + B;
//!         C = B;
//!         println!("{A} {B} {C}");
//!         C = A;
//!     }
//! }
//! ```
//!
//! 似乎存储在存储器中的某些变量已更改,执行了加法运算,结果存储在 `A` 中,并且变量 `C` 被修改了两次。
//!
//! 当仅涉及单个线程时,结果如预期的那样:
//! `7 4 4` 行被打印。
//!
//! 至于幕后发生的情况,启用优化后,最终生成的机器代码可能看起来与代码有很大不同:
//!
//! - `C` 的第一个存储区可能在存储区移至 `A` 或 `B` 之前已被移至 _as if_。
//!
//! - 可以删除 `A + B` 到 `A` 的分配,因为总和可以存储在一个临时位置,直到打印出来为止,并且变量永远不会更新。
//!
//! - 最终结果可以仅通过在编译时查看代码来确定,因此 [常量合并][constant folding] 可能会将整个块变成一个简单的 `println!("7 4 4")`。
//!
//! 只要最终的优化代码在执行时产生的结果与没有优化的结果相同,编译器就可以执行这些优化的任何组合。
//!
//! 由于现代计算机中使用了 [并发][concurrency],因此有关程序执行顺序的假设通常是错误的。
//! 访问全局变量会导致不确定的结果,即使编译器优化被禁用,仍然可能引入同步错误。
//!
//! 请注意,由于 Rust 的安全保证,假设我们在此模块中未使用任何同步原语,则访问 (static) 变量需要 `unsafe` 代码。
//!
//! [constant folding]: https://en.wikipedia.org/wiki/Constant_folding
//! [concurrency]: https://en.wikipedia.org/wiki/Concurrency_(computer_science)
//!
//! ## 乱序执行
//!
//! 由于多种原因,指令的执行顺序与我们定义的顺序可以不同:
//!
//! - **编译器** 重新排序指令:如果编译器可以在较早的时候发出指令,它将尝试这样做。
//! 例如,它可能会在代码块的顶部提升内存负载,以便 CPU 可以从内存中启动 [预取][prefetching] 值。
//!
//!   在单线程方案中,这可能会在编写信号处理程序或某些类型的代码时引起问题。
//!   使用 [编译器栅栏][compiler fences] 来防止这种重新排序。
//!
//! - 一个单处理器执行指令 [乱序][out-of-order]:
//!   现代的 CPU 能够执行 [超标量][superscalar],也就是说,多个指令可能同时执行,即使机器代码描述的是一个顺序过程。
//!
//!   这种重新排序由 CPU 透明地处理。
//!
//! - 同时执行多个硬件线程的 **多处理器** 系统:在多线程方案中,可以使用两种原语来处理同步:
//!   - [内存栅栏][memory fences] 以确保以正确的顺序对其他 CPU 进行内存访问。
//!   - [原子操作][atomic operations] 以确保同时访问同一内存位置不会导致未定义的行为。
//!
//! [prefetching]: https://en.wikipedia.org/wiki/Cache_prefetching
//! [compiler fences]: crate::sync::atomic::compiler_fence
//! [out-of-order]: https://en.wikipedia.org/wiki/Out-of-order_execution
//! [superscalar]: https://en.wikipedia.org/wiki/Superscalar_processor
//! [memory fences]: crate::sync::atomic::fence
//! [atomic operations]: crate::sync::atomic
//!
//! ## 更高级别的同步对象
//!
//! 大多数同步原语都非常容易出错,使用起来也不方便,这就是为什么标准库还公开了一些更高级别的同步对象的原因。
//!
//! 这些抽象可以在较低级别的原语基础上构建。
//! 为了提高效率,标准库中的同步对象通常是在操作系统内核的帮助下实现的,该内核可以在线程被锁定而被阻塞时重新安排线程的时间。
//!
//!
//! 以下是可用的同步对象的概述:
//!
//! - [`Arc`]: 原子引用计数指针,可以在多线程环境中使用,延长某些数据的生命周期,直到所有线程都执行完为止。
//!
//! - [`Barrier`]: 确保多个线程将等待彼此到达程序中的某个点,然后再一起继续执行。
//!
//! - [`Condvar`]: 条件变量,提供在等待事件发生时阻塞线程的能力。
//!
//! - [`mpsc`]: 多生产者、单消费者队列,用于基于消息的通信。可以提供轻量级的线程间同步机制,但要花一些额外的内存。
//!
//! - [`Mutex`]: 互斥机制,保证一次最多有一个线程可以访问一些数据。
//!
//! - [`Once`]: 用于线程安全的一次性全局初始化例程
//!
//! - [`OnceLock`]: 用于全局变量的线程安全的一次性初始化。
//!
//! - [`RwLock`]: 提供一种互斥机制,允许同时有多个 readers,但一次只允许一个 writer。在某些情况下,这可能比互斥锁更有效。
//!
//! [`Arc`]: crate::sync::Arc
//! [`Barrier`]: crate::sync::Barrier
//! [`Condvar`]: crate::sync::Condvar
//! [`mpsc`]: crate::sync::mpsc
//! [`Mutex`]: crate::sync::Mutex
//! [`Once`]: crate::sync::Once
//! [`OnceLock`]: crate::sync::OnceLock
//! [`RwLock`]: crate::sync::RwLock
//!
//!
//!
//!
//!
//!
//!
//!
//!
//!
//!
//!
//!
//!
//!
//!
//!
//!
//!
//!
//!
//!
//!
//!
//!
//!
//!
//!
//!
//!
//!
//!
//!
//!
//!
//!
//!
//!
//!
//!
//!
//!
//!
//!
//!

#![stable(feature = "rust1", since = "1.0.0")]

#[stable(feature = "rust1", since = "1.0.0")]
pub use alloc_crate::sync::{Arc, Weak};
#[stable(feature = "rust1", since = "1.0.0")]
pub use core::sync::atomic;
#[unstable(feature = "exclusive_wrapper", issue = "98407")]
pub use core::sync::Exclusive;

#[stable(feature = "rust1", since = "1.0.0")]
pub use self::barrier::{Barrier, BarrierWaitResult};
#[stable(feature = "rust1", since = "1.0.0")]
pub use self::condvar::{Condvar, WaitTimeoutResult};
#[stable(feature = "rust1", since = "1.0.0")]
pub use self::mutex::{Mutex, MutexGuard};
#[stable(feature = "rust1", since = "1.0.0")]
#[allow(deprecated)]
pub use self::once::{Once, OnceState, ONCE_INIT};
#[stable(feature = "rust1", since = "1.0.0")]
pub use self::poison::{LockResult, PoisonError, TryLockError, TryLockResult};
#[stable(feature = "rust1", since = "1.0.0")]
pub use self::rwlock::{RwLock, RwLockReadGuard, RwLockWriteGuard};

#[unstable(feature = "lazy_cell", issue = "109736")]
pub use self::lazy_lock::LazyLock;
#[stable(feature = "once_cell", since = "1.70.0")]
pub use self::once_lock::OnceLock;

pub(crate) use self::remutex::{ReentrantMutex, ReentrantMutexGuard};

pub mod mpsc;

mod barrier;
mod condvar;
mod lazy_lock;
mod mpmc;
mod mutex;
pub(crate) mod once;
mod once_lock;
mod poison;
mod remutex;
mod rwlock;