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