1#[cfg(test)]
2mod tests;
3
4use crate::fmt;
5use crate::sync::{Condvar, Mutex};
6
7/// A barrier enables multiple threads to synchronize the beginning
8/// of some computation.
9///
10/// # Examples
11///
12/// ```
13/// use std::sync::{Arc, Barrier};
14/// use std::thread;
15///
16/// let n = 10;
17/// let mut handles = Vec::with_capacity(n);
18/// let barrier = Arc::new(Barrier::new(n));
19/// for _ in 0..n {
20/// let c = Arc::clone(&barrier);
21/// // The same messages will be printed together.
22/// // You will NOT see any interleaving.
23/// handles.push(thread::spawn(move|| {
24/// println!("before wait");
25/// c.wait();
26/// println!("after wait");
27/// }));
28/// }
29/// // Wait for other threads to finish.
30/// for handle in handles {
31/// handle.join().unwrap();
32/// }
33/// ```
34#[stable(feature = "rust1", since = "1.0.0")]
35pub struct Barrier {
36 lock: Mutex<BarrierState>,
37 cvar: Condvar,
38 num_threads: usize,
39}
40
41// The inner state of a double barrier
42struct BarrierState {
43 count: usize,
44 generation_id: usize,
45}
46
47/// A `BarrierWaitResult` is returned by [`Barrier::wait()`] when all threads
48/// in the [`Barrier`] have rendezvoused.
49///
50/// # Examples
51///
52/// ```
53/// use std::sync::Barrier;
54///
55/// let barrier = Barrier::new(1);
56/// let barrier_wait_result = barrier.wait();
57/// ```
58#[stable(feature = "rust1", since = "1.0.0")]
59pub struct BarrierWaitResult(bool);
60
61#[stable(feature = "std_debug", since = "1.16.0")]
62impl fmt::Debug for Barrier {
63 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
64 f.debug_struct(name:"Barrier").finish_non_exhaustive()
65 }
66}
67
68impl Barrier {
69 /// Creates a new barrier that can block a given number of threads.
70 ///
71 /// A barrier will block `n`-1 threads which call [`wait()`] and then wake
72 /// up all threads at once when the `n`th thread calls [`wait()`].
73 ///
74 /// [`wait()`]: Barrier::wait
75 ///
76 /// # Examples
77 ///
78 /// ```
79 /// use std::sync::Barrier;
80 ///
81 /// let barrier = Barrier::new(10);
82 /// ```
83 #[stable(feature = "rust1", since = "1.0.0")]
84 #[rustc_const_stable(feature = "const_barrier", since = "1.78.0")]
85 #[must_use]
86 #[inline]
87 pub const fn new(n: usize) -> Barrier {
88 Barrier {
89 lock: Mutex::new(BarrierState { count: 0, generation_id: 0 }),
90 cvar: Condvar::new(),
91 num_threads: n,
92 }
93 }
94
95 /// Blocks the current thread until all threads have rendezvoused here.
96 ///
97 /// Barriers are re-usable after all threads have rendezvoused once, and can
98 /// be used continuously.
99 ///
100 /// A single (arbitrary) thread will receive a [`BarrierWaitResult`] that
101 /// returns `true` from [`BarrierWaitResult::is_leader()`] when returning
102 /// from this function, and all other threads will receive a result that
103 /// will return `false` from [`BarrierWaitResult::is_leader()`].
104 ///
105 /// # Examples
106 ///
107 /// ```
108 /// use std::sync::{Arc, Barrier};
109 /// use std::thread;
110 ///
111 /// let n = 10;
112 /// let mut handles = Vec::with_capacity(n);
113 /// let barrier = Arc::new(Barrier::new(n));
114 /// for _ in 0..n {
115 /// let c = Arc::clone(&barrier);
116 /// // The same messages will be printed together.
117 /// // You will NOT see any interleaving.
118 /// handles.push(thread::spawn(move|| {
119 /// println!("before wait");
120 /// c.wait();
121 /// println!("after wait");
122 /// }));
123 /// }
124 /// // Wait for other threads to finish.
125 /// for handle in handles {
126 /// handle.join().unwrap();
127 /// }
128 /// ```
129 #[stable(feature = "rust1", since = "1.0.0")]
130 pub fn wait(&self) -> BarrierWaitResult {
131 let mut lock = self.lock.lock().unwrap();
132 let local_gen = lock.generation_id;
133 lock.count += 1;
134 if lock.count < self.num_threads {
135 let _guard =
136 self.cvar.wait_while(lock, |state| local_gen == state.generation_id).unwrap();
137 BarrierWaitResult(false)
138 } else {
139 lock.count = 0;
140 lock.generation_id = lock.generation_id.wrapping_add(1);
141 self.cvar.notify_all();
142 BarrierWaitResult(true)
143 }
144 }
145}
146
147#[stable(feature = "std_debug", since = "1.16.0")]
148impl fmt::Debug for BarrierWaitResult {
149 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
150 f.debug_struct("BarrierWaitResult").field(name:"is_leader", &self.is_leader()).finish()
151 }
152}
153
154impl BarrierWaitResult {
155 /// Returns `true` if this thread is the "leader thread" for the call to
156 /// [`Barrier::wait()`].
157 ///
158 /// Only one thread will have `true` returned from their result, all other
159 /// threads will have `false` returned.
160 ///
161 /// # Examples
162 ///
163 /// ```
164 /// use std::sync::Barrier;
165 ///
166 /// let barrier = Barrier::new(1);
167 /// let barrier_wait_result = barrier.wait();
168 /// println!("{:?}", barrier_wait_result.is_leader());
169 /// ```
170 #[stable(feature = "rust1", since = "1.0.0")]
171 #[must_use]
172 pub fn is_leader(&self) -> bool {
173 self.0
174 }
175}
176