Thanks to visit codestin.com
Credit goes to doc.rust-lang.org

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}