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