std/sync/nonpoison/
condvar.rs

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