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

#
std/sync/nonpoison/
condvar.rs

    1use crate::fmt;
    2use crate::ops::DerefMut;
    3use crate::sync::WaitTimeoutResult;
    4use crate::sync::nonpoison::{MutexGuard, mutex};
    5use crate::sys::sync as sys;
    6use crate::time::{Duration, Instant};
    7
    8/// A Condition Variable
    9///
    10/// For more information about condition variables, check out the documentation for the poisoning
    11/// variant of this type at [`poison::Condvar`].
    12///
    13/// # Examples
    14///
    15/// Note that this `Condvar` does **not** propagate information about threads that panic while
    16/// holding a lock. If you need this functionality, see [`poison::Mutex`] and [`poison::Condvar`].
    17///
    18/// ```
    19/// #![feature(nonpoison_mutex)]
    20/// #![feature(nonpoison_condvar)]
    21///
    22/// use std::sync::nonpoison::{Mutex, Condvar};
    23/// use std::sync::Arc;
    24/// use std::thread;
    25///
    26/// let pair = Arc::new((Mutex::new(false), Condvar::new()));
    27/// let pair2 = Arc::clone(&pair);
    28///
    29/// // Inside of our lock, spawn a new thread, and then wait for it to start.
    30/// thread::spawn(move || {
    31///     let (lock, cvar) = &*pair2;
    32///     let mut started = lock.lock();
    33///     *started = true;
    34///     // We notify the condvar that the value has changed.
    35///     cvar.notify_one();
    36/// });
    37///
    38/// // Wait for the thread to start up.
    39/// let (lock, cvar) = &*pair;
    40/// let mut started = lock.lock();
    41/// while !*started {
    42///     cvar.wait(&mut started);
    43/// }
    44/// ```
    45///
    46/// [`poison::Mutex`]: crate::sync::poison::Mutex
    47/// [`poison::Condvar`]: crate::sync::poison::Condvar
    48#[unstable(feature = "nonpoison_condvar", issue = "134645")]
    49pub struct Condvar {
    50    inner: sys::Condvar,
    51}
    52
    53impl Condvar {
    54    /// Creates a new condition variable which is ready to be waited on and
    55    /// notified.
    56    ///
    57    /// # Examples
    58    ///
    59    /// ```
    60    /// use std::sync::Condvar;
    61    ///
    62    /// let condvar = Condvar::new();
    63    /// ```
    64    #[unstable(feature = "nonpoison_condvar", issue = "134645")]
    65    #[must_use]
    66    #[inline]
    67    pub const fn new() -> Condvar {
    68        Condvar { inner: sys::Condvar::new() }
    69    }
    70
    71    /// Blocks the current thread until this condition variable receives a
    72    /// notification.
    73    ///
    74    /// This function will atomically unlock the mutex specified (represented by
    75    /// `guard`) and block the current thread. This means that any calls
    76    /// to [`notify_one`] or [`notify_all`] which happen logically after the
    77    /// mutex is unlocked are candidates to wake this thread up. When this
    78    /// function call returns, the lock specified will have been re-acquired.
    79    ///
    80    /// Note that this function is susceptible to spurious wakeups. Condition
    81    /// variables normally have a boolean predicate associated with them, and
    82    /// the predicate must always be checked each time this function returns to
    83    /// protect against spurious wakeups.
    84    ///
    85    /// # Panics
    86    ///
    87    /// This function may [`panic!`] if it is used with more than one mutex
    88    /// over time.
    89    ///
    90    /// [`notify_one`]: Self::notify_one
    91    /// [`notify_all`]: Self::notify_all
    92    ///
    93    /// # Examples
    94    ///
    95    /// ```
    96    /// #![feature(nonpoison_mutex)]
    97    /// #![feature(nonpoison_condvar)]
    98    ///
    99    /// use std::sync::nonpoison::{Mutex, Condvar};
    100    /// use std::sync::Arc;
    101    /// use std::thread;
    102    ///
    103    /// let pair = Arc::new((Mutex::new(false), Condvar::new()));
    104    /// let pair2 = Arc::clone(&pair);
    105    ///
    106    /// thread::spawn(move || {
    107    ///     let (lock, cvar) = &*pair2;
    108    ///     let mut started = lock.lock();
    109    ///     *started = true;
    110    ///     // We notify the condvar that the value has changed.
    111    ///     cvar.notify_one();
    112    /// });
    113    ///
    114    /// // Wait for the thread to start up.
    115    /// let (lock, cvar) = &*pair;
    116    /// let mut started = lock.lock();
    117    /// // As long as the value inside the `Mutex<bool>` is `false`, we wait.
    118    /// while !*started {
    119    ///     cvar.wait(&mut started);
    120    /// }
    121    /// ```
    122    #[unstable(feature = "nonpoison_condvar", issue = "134645")]
    123    pub fn wait<T>(&self, guard: &mut MutexGuard<'_, T>) {
    124        unsafe {
    125            let lock = mutex::guard_lock(guard);
    126            self.inner.wait(lock);
    127        }
    128    }
    129
    130    /// Blocks the current thread until the provided condition becomes false.
    131    ///
    132    /// `condition` is checked immediately; if not met (returns `true`), this
    133    /// will [`wait`] for the next notification then check again. This repeats
    134    /// until `condition` returns `false`, in which case this function returns.
    135    ///
    136    /// This function will atomically unlock the mutex specified (represented by
    137    /// `guard`) and block the current thread. This means that any calls
    138    /// to [`notify_one`] or [`notify_all`] which happen logically after the
    139    /// mutex is unlocked are candidates to wake this thread up. When this
    140    /// function call returns, the lock specified will have been re-acquired.
    141    ///
    142    /// [`wait`]: Self::wait
    143    /// [`notify_one`]: Self::notify_one
    144    /// [`notify_all`]: Self::notify_all
    145    ///
    146    /// # Examples
    147    ///
    148    /// ```
    149    /// #![feature(nonpoison_mutex)]
    150    /// #![feature(nonpoison_condvar)]
    151    ///
    152    /// use std::sync::nonpoison::{Mutex, Condvar};
    153    /// use std::sync::Arc;
    154    /// use std::thread;
    155    ///
    156    /// let pair = Arc::new((Mutex::new(true), Condvar::new()));
    157    /// let pair2 = Arc::clone(&pair);
    158    ///
    159    /// thread::spawn(move || {
    160    ///     let (lock, cvar) = &*pair2;
    161    ///     let mut pending = lock.lock();
    162    ///     *pending = false;
    163    ///     // We notify the condvar that the value has changed.
    164    ///     cvar.notify_one();
    165    /// });
    166    ///
    167    /// // Wait for the thread to start up.
    168    /// let (lock, cvar) = &*pair;
    169    /// // As long as the value inside the `Mutex<bool>` is `true`, we wait.
    170    /// let mut guard = lock.lock();
    171    /// cvar.wait_while(&mut guard, |pending| { *pending });
    172    /// ```
    173    #[unstable(feature = "nonpoison_condvar", issue = "134645")]
    174    pub fn wait_while<T, F>(&self, guard: &mut MutexGuard<'_, T>, mut condition: F)
    175    where
    176        F: FnMut(&mut T) -> bool,
    177    {
    178        while condition(guard.deref_mut()) {
    179            self.wait(guard);
    180        }
    181    }
    182
    183    /// Waits on this condition variable for a notification, timing out after a
    184    /// specified duration.
    185    ///
    186    /// The semantics of this function are equivalent to [`wait`] except that
    187    /// the thread will be blocked for roughly no longer than `dur`. This
    188    /// method should not be used for precise timing due to anomalies such as
    189    /// preemption or platform differences that might not cause the maximum
    190    /// amount of time waited to be precisely `dur`.
    191    ///
    192    /// Note that the best effort is made to ensure that the time waited is
    193    /// measured with a monotonic clock, and not affected by the changes made to
    194    /// the system time. This function is susceptible to spurious wakeups.
    195    /// Condition variables normally have a boolean predicate associated with
    196    /// them, and the predicate must always be checked each time this function
    197    /// returns to protect against spurious wakeups.  Furthermore, since the timeout
    198    /// is given relative to the moment this function is called, it needs to be adjusted
    199    /// when this function is called in a loop. The [`wait_timeout_while`] method
    200    /// lets you wait with a timeout while a predicate is true, taking care of all these concerns.
    201    ///
    202    /// The returned [`WaitTimeoutResult`] value indicates if the timeout is
    203    /// known to have elapsed.
    204    ///
    205    /// Like [`wait`], the lock specified will have been re-acquired when this function
    206    /// returns, regardless of whether the timeout elapsed or not.
    207    ///
    208    /// [`wait`]: Self::wait
    209    /// [`wait_timeout_while`]: Self::wait_timeout_while
    210    ///
    211    /// # Examples
    212    ///
    213    /// ```
    214    /// #![feature(nonpoison_mutex)]
    215    /// #![feature(nonpoison_condvar)]
    216    ///
    217    /// use std::sync::nonpoison::{Mutex, Condvar};
    218    /// use std::sync::Arc;
    219    /// use std::thread;
    220    /// use std::time::Duration;
    221    ///
    222    /// let pair = Arc::new((Mutex::new(false), Condvar::new()));
    223    /// let pair2 = Arc::clone(&pair);
    224    ///
    225    /// thread::spawn(move || {
    226    ///     let (lock, cvar) = &*pair2;
    227    ///     let mut started = lock.lock();
    228    ///     *started = true;
    229    ///     // We notify the condvar that the value has changed.
    230    ///     cvar.notify_one();
    231    /// });
    232    ///
    233    /// // wait for the thread to start up
    234    /// let (lock, cvar) = &*pair;
    235    /// let mut started = lock.lock();
    236    /// // as long as the value inside the `Mutex<bool>` is `false`, we wait
    237    /// loop {
    238    ///     let result = cvar.wait_timeout(&mut started, Duration::from_millis(10));
    239    ///     // 10 milliseconds have passed, or maybe the value changed!
    240    ///     if *started == true {
    241    ///         // We received the notification and the value has been updated, we can leave.
    242    ///         break
    243    ///     }
    244    /// }
    245    /// ```
    246    #[unstable(feature = "nonpoison_condvar", issue = "134645")]
    247    pub fn wait_timeout<T>(
    248        &self,
    249        guard: &mut MutexGuard<'_, T>,
    250        dur: Duration,
    251    ) -> WaitTimeoutResult {
    252        let success = unsafe {
    253            let lock = mutex::guard_lock(guard);
    254            self.inner.wait_timeout(lock, dur)
    255        };
    256        WaitTimeoutResult(!success)
    257    }
    258
    259    /// Waits on this condition variable for a notification, timing out after a
    260    /// specified duration.
    261    ///
    262    /// The semantics of this function are equivalent to [`wait_while`] except
    263    /// that the thread will be blocked for roughly no longer than `dur`. This
    264    /// method should not be used for precise timing due to anomalies such as
    265    /// preemption or platform differences that might not cause the maximum
    266    /// amount of time waited to be precisely `dur`.
    267    ///
    268    /// Note that the best effort is made to ensure that the time waited is
    269    /// measured with a monotonic clock, and not affected by the changes made to
    270    /// the system time.
    271    ///
    272    /// The returned [`WaitTimeoutResult`] value indicates if the timeout is
    273    /// known to have elapsed without the condition being met.
    274    ///
    275    /// Like [`wait_while`], the lock specified will have been re-acquired when this
    276    /// function returns, regardless of whether the timeout elapsed or not.
    277    ///
    278    /// [`wait_while`]: Self::wait_while
    279    /// [`wait_timeout`]: Self::wait_timeout
    280    ///
    281    /// # Examples
    282    ///
    283    /// ```
    284    /// #![feature(nonpoison_mutex)]
    285    /// #![feature(nonpoison_condvar)]
    286    ///
    287    /// use std::sync::nonpoison::{Mutex, Condvar};
    288    /// use std::sync::Arc;
    289    /// use std::thread;
    290    /// use std::time::Duration;
    291    ///
    292    /// let pair = Arc::new((Mutex::new(true), Condvar::new()));
    293    /// let pair2 = Arc::clone(&pair);
    294    ///
    295    /// thread::spawn(move || {
    296    ///     let (lock, cvar) = &*pair2;
    297    ///     let mut pending = lock.lock();
    298    ///     *pending = false;
    299    ///     // We notify the condvar that the value has changed.
    300    ///     cvar.notify_one();
    301    /// });
    302    ///
    303    /// // wait for the thread to start up
    304    /// let (lock, cvar) = &*pair;
    305    /// let mut guard = lock.lock();
    306    /// let result = cvar.wait_timeout_while(
    307    ///     &mut guard,
    308    ///     Duration::from_millis(100),
    309    ///     |&mut pending| pending,
    310    /// );
    311    /// if result.timed_out() {
    312    ///     // timed-out without the condition ever evaluating to false.
    313    /// }
    314    /// // access the locked mutex via guard
    315    /// ```
    316    #[unstable(feature = "nonpoison_condvar", issue = "134645")]
    317    pub fn wait_timeout_while<T, F>(
    318        &self,
    319        guard: &mut MutexGuard<'_, T>,
    320        dur: Duration,
    321        mut condition: F,
    322    ) -> WaitTimeoutResult
    323    where
    324        F: FnMut(&mut T) -> bool,
    325    {
    326        let start = Instant::now();
    327
    328        while condition(guard.deref_mut()) {
    329            let timeout = match dur.checked_sub(start.elapsed()) {
    330                Some(timeout) => timeout,
    331                None => return WaitTimeoutResult(true),
    332            };
    333
    334            self.wait_timeout(guard, timeout);
    335        }
    336
    337        WaitTimeoutResult(false)
    338    }
    339
    340    /// Wakes up one blocked thread on this condvar.
    341    ///
    342    /// If there is a blocked thread on this condition variable, then it will
    343    /// be woken up from its call to [`wait`] or [`wait_timeout`]. Calls to
    344    /// `notify_one` are not buffered in any way.
    345    ///
    346    /// To wake up all threads, see [`notify_all`].
    347    ///
    348    /// [`wait`]: Self::wait
    349    /// [`wait_timeout`]: Self::wait_timeout
    350    /// [`notify_all`]: Self::notify_all
    351    ///
    352    /// # Examples
    353    ///
    354    /// ```
    355    /// #![feature(nonpoison_mutex)]
    356    /// #![feature(nonpoison_condvar)]
    357    ///
    358    /// use std::sync::nonpoison::{Mutex, Condvar};
    359    /// use std::sync::Arc;
    360    /// use std::thread;
    361    ///
    362    /// let pair = Arc::new((Mutex::new(false), Condvar::new()));
    363    /// let pair2 = Arc::clone(&pair);
    364    ///
    365    /// thread::spawn(move || {
    366    ///     let (lock, cvar) = &*pair2;
    367    ///     let mut started = lock.lock();
    368    ///     *started = true;
    369    ///     // We notify the condvar that the value has changed.
    370    ///     cvar.notify_one();
    371    /// });
    372    ///
    373    /// // Wait for the thread to start up.
    374    /// let (lock, cvar) = &*pair;
    375    /// let mut started = lock.lock();
    376    /// // As long as the value inside the `Mutex<bool>` is `false`, we wait.
    377    /// while !*started {
    378    ///     cvar.wait(&mut started);
    379    /// }
    380    /// ```
    381    #[unstable(feature = "nonpoison_condvar", issue = "134645")]
    382    pub fn notify_one(&self) {
    383        self.inner.notify_one()
    384    }
    385
    386    /// Wakes up all blocked threads on this condvar.
    387    ///
    388    /// This method will ensure that any current waiters on the condition
    389    /// variable are awoken. Calls to `notify_all()` are not buffered in any
    390    /// way.
    391    ///
    392    /// To wake up only one thread, see [`notify_one`].
    393    ///
    394    /// [`notify_one`]: Self::notify_one
    395    ///
    396    /// # Examples
    397    ///
    398    /// ```
    399    /// #![feature(nonpoison_mutex)]
    400    /// #![feature(nonpoison_condvar)]
    401    ///
    402    /// use std::sync::nonpoison::{Mutex, Condvar};
    403    /// use std::sync::Arc;
    404    /// use std::thread;
    405    ///
    406    /// let pair = Arc::new((Mutex::new(false), Condvar::new()));
    407    /// let pair2 = Arc::clone(&pair);
    408    ///
    409    /// thread::spawn(move || {
    410    ///     let (lock, cvar) = &*pair2;
    411    ///     let mut started = lock.lock();
    412    ///     *started = true;
    413    ///     // We notify the condvar that the value has changed.
    414    ///     cvar.notify_all();
    415    /// });
    416    ///
    417    /// // Wait for the thread to start up.
    418    /// let (lock, cvar) = &*pair;
    419    /// let mut started = lock.lock();
    420    /// // As long as the value inside the `Mutex<bool>` is `false`, we wait.
    421    /// while !*started {
    422    ///     cvar.wait(&mut started);
    423    /// }
    424    /// ```
    425    #[unstable(feature = "nonpoison_condvar", issue = "134645")]
    426    pub fn notify_all(&self) {
    427        self.inner.notify_all()
    428    }
    429}
    430
    431#[unstable(feature = "nonpoison_condvar", issue = "134645")]
    432impl fmt::Debug for Condvar {
    433    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
    434        f.debug_struct("Condvar").finish_non_exhaustive()
    435    }
    436}
    437
    438#[unstable(feature = "nonpoison_condvar", issue = "134645")]
    439impl Default for Condvar {
    440    /// Creates a `Condvar` which is ready to be waited on and notified.
    441    fn default() -> Condvar {
    442        Condvar::new()
    443    }
    444}