barrier.rs - source
Description: Source of the Rust file `library/std/src/sync/barrier.rs`.

#
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 all threads which call [`wait()`] until the `n`th thread calls [`wait()`],
    69    /// and then wake up all threads at once.
    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            self.cvar.wait_while(&mut 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}