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.  Furthermore, since the timeout
202    /// is given relative to the moment this function is called, it needs to be adjusted
203    /// when this function is called in a loop. The [`wait_timeout_while`] method
204    /// lets you wait with a timeout while a predicate is true, taking care of all these concerns.
205    ///
206    /// The returned [`WaitTimeoutResult`] value indicates if the timeout is
207    /// known to have elapsed.
208    ///
209    /// Like [`wait`], the lock specified will be re-acquired when this function
210    /// returns, regardless of whether the timeout elapsed or not.
211    ///
212    /// [`wait`]: Self::wait
213    /// [`wait_timeout_while`]: Self::wait_timeout_while
214    ///
215    /// # Examples
216    ///
217    /// ```
218    /// #![feature(nonpoison_mutex)]
219    /// #![feature(nonpoison_condvar)]
220    ///
221    /// use std::sync::nonpoison::{Mutex, Condvar};
222    /// use std::sync::Arc;
223    /// use std::thread;
224    /// use std::time::Duration;
225    ///
226    /// let pair = Arc::new((Mutex::new(false), Condvar::new()));
227    /// let pair2 = Arc::clone(&pair);
228    ///
229    /// thread::spawn(move || {
230    ///     let (lock, cvar) = &*pair2;
231    ///     let mut started = lock.lock();
232    ///     *started = true;
233    ///     // We notify the condvar that the value has changed.
234    ///     cvar.notify_one();
235    /// });
236    ///
237    /// // wait for the thread to start up
238    /// let (lock, cvar) = &*pair;
239    /// let mut started = lock.lock();
240    /// // as long as the value inside the `Mutex<bool>` is `false`, we wait
241    /// loop {
242    ///     let result = cvar.wait_timeout(started, Duration::from_millis(10));
243    ///     // 10 milliseconds have passed, or maybe the value changed!
244    ///     started = result.0;
245    ///     if *started == true {
246    ///         // We received the notification and the value has been updated, we can leave.
247    ///         break
248    ///     }
249    /// }
250    /// ```
251    #[unstable(feature = "nonpoison_condvar", issue = "134645")]
252    pub fn wait_timeout<'a, T>(
253        &self,
254        guard: MutexGuard<'a, T>,
255        dur: Duration,
256    ) -> (MutexGuard<'a, T>, WaitTimeoutResult) {
257        let success = unsafe {
258            let lock = mutex::guard_lock(&guard);
259            self.inner.wait_timeout(lock, dur)
260        };
261        (guard, WaitTimeoutResult(!success))
262    }
263
264    /// Waits on this condition variable for a notification, timing out after a
265    /// specified duration.
266    ///
267    /// The semantics of this function are equivalent to [`wait_while`] except
268    /// that the thread will be blocked for roughly no longer than `dur`. This
269    /// method should not be used for precise timing due to anomalies such as
270    /// preemption or platform differences that might not cause the maximum
271    /// amount of time waited to be precisely `dur`.
272    ///
273    /// Note that the best effort is made to ensure that the time waited is
274    /// measured with a monotonic clock, and not affected by the changes made to
275    /// the system time.
276    ///
277    /// The returned [`WaitTimeoutResult`] value indicates if the timeout is
278    /// known to have elapsed without the condition being met.
279    ///
280    /// Like [`wait_while`], the lock specified will be re-acquired when this
281    /// function returns, regardless of whether the timeout elapsed or not.
282    ///
283    /// [`wait_while`]: Self::wait_while
284    /// [`wait_timeout`]: Self::wait_timeout
285    ///
286    /// # Examples
287    ///
288    /// ```
289    /// #![feature(nonpoison_mutex)]
290    /// #![feature(nonpoison_condvar)]
291    ///
292    /// use std::sync::nonpoison::{Mutex, Condvar};
293    /// use std::sync::Arc;
294    /// use std::thread;
295    /// use std::time::Duration;
296    ///
297    /// let pair = Arc::new((Mutex::new(true), Condvar::new()));
298    /// let pair2 = Arc::clone(&pair);
299    ///
300    /// thread::spawn(move || {
301    ///     let (lock, cvar) = &*pair2;
302    ///     let mut pending = lock.lock();
303    ///     *pending = false;
304    ///     // We notify the condvar that the value has changed.
305    ///     cvar.notify_one();
306    /// });
307    ///
308    /// // wait for the thread to start up
309    /// let (lock, cvar) = &*pair;
310    /// let result = cvar.wait_timeout_while(
311    ///     lock.lock(),
312    ///     Duration::from_millis(100),
313    ///     |&mut pending| pending,
314    /// );
315    /// if result.1.timed_out() {
316    ///     // timed-out without the condition ever evaluating to false.
317    /// }
318    /// // access the locked mutex via result.0
319    /// ```
320    #[unstable(feature = "nonpoison_condvar", issue = "134645")]
321    pub fn wait_timeout_while<'a, T, F>(
322        &self,
323        mut guard: MutexGuard<'a, T>,
324        dur: Duration,
325        mut condition: F,
326    ) -> (MutexGuard<'a, T>, WaitTimeoutResult)
327    where
328        F: FnMut(&mut T) -> bool,
329    {
330        let start = Instant::now();
331        loop {
332            if !condition(&mut *guard) {
333                return (guard, WaitTimeoutResult(false));
334            }
335            let timeout = match dur.checked_sub(start.elapsed()) {
336                Some(timeout) => timeout,
337                None => return (guard, WaitTimeoutResult(true)),
338            };
339            guard = self.wait_timeout(guard, timeout).0;
340        }
341    }
342
343    /// Wakes up one blocked thread on this condvar.
344    ///
345    /// If there is a blocked thread on this condition variable, then it will
346    /// be woken up from its call to [`wait`] or [`wait_timeout`]. Calls to
347    /// `notify_one` are not buffered in any way.
348    ///
349    /// To wake up all threads, see [`notify_all`].
350    ///
351    /// [`wait`]: Self::wait
352    /// [`wait_timeout`]: Self::wait_timeout
353    /// [`notify_all`]: Self::notify_all
354    ///
355    /// # Examples
356    ///
357    /// ```
358    /// #![feature(nonpoison_mutex)]
359    /// #![feature(nonpoison_condvar)]
360    ///
361    /// use std::sync::nonpoison::{Mutex, Condvar};
362    /// use std::sync::Arc;
363    /// use std::thread;
364    ///
365    /// let pair = Arc::new((Mutex::new(false), Condvar::new()));
366    /// let pair2 = Arc::clone(&pair);
367    ///
368    /// thread::spawn(move || {
369    ///     let (lock, cvar) = &*pair2;
370    ///     let mut started = lock.lock();
371    ///     *started = true;
372    ///     // We notify the condvar that the value has changed.
373    ///     cvar.notify_one();
374    /// });
375    ///
376    /// // Wait for the thread to start up.
377    /// let (lock, cvar) = &*pair;
378    /// let mut started = lock.lock();
379    /// // As long as the value inside the `Mutex<bool>` is `false`, we wait.
380    /// while !*started {
381    ///     started = cvar.wait(started);
382    /// }
383    /// ```
384    #[unstable(feature = "nonpoison_condvar", issue = "134645")]
385    pub fn notify_one(&self) {
386        self.inner.notify_one()
387    }
388
389    /// Wakes up all blocked threads on this condvar.
390    ///
391    /// This method will ensure that any current waiters on the condition
392    /// variable are awoken. Calls to `notify_all()` are not buffered in any
393    /// way.
394    ///
395    /// To wake up only one thread, see [`notify_one`].
396    ///
397    /// [`notify_one`]: Self::notify_one
398    ///
399    /// # Examples
400    ///
401    /// ```
402    /// #![feature(nonpoison_mutex)]
403    /// #![feature(nonpoison_condvar)]
404    ///
405    /// use std::sync::nonpoison::{Mutex, Condvar};
406    /// use std::sync::Arc;
407    /// use std::thread;
408    ///
409    /// let pair = Arc::new((Mutex::new(false), Condvar::new()));
410    /// let pair2 = Arc::clone(&pair);
411    ///
412    /// thread::spawn(move || {
413    ///     let (lock, cvar) = &*pair2;
414    ///     let mut started = lock.lock();
415    ///     *started = true;
416    ///     // We notify the condvar that the value has changed.
417    ///     cvar.notify_all();
418    /// });
419    ///
420    /// // Wait for the thread to start up.
421    /// let (lock, cvar) = &*pair;
422    /// let mut started = lock.lock();
423    /// // As long as the value inside the `Mutex<bool>` is `false`, we wait.
424    /// while !*started {
425    ///     started = cvar.wait(started);
426    /// }
427    /// ```
428    #[unstable(feature = "nonpoison_condvar", issue = "134645")]
429    pub fn notify_all(&self) {
430        self.inner.notify_all()
431    }
432}
433
434#[unstable(feature = "nonpoison_condvar", issue = "134645")]
435impl fmt::Debug for Condvar {
436    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
437        f.debug_struct("Condvar").finish_non_exhaustive()
438    }
439}
440
441#[unstable(feature = "nonpoison_condvar", issue = "134645")]
442impl Default for Condvar {
443    /// Creates a `Condvar` which is ready to be waited on and notified.
444    fn default() -> Condvar {
445        Condvar::new()
446    }
447}