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}