std/sync/poison/
condvar.rs

1use crate::fmt;
2use crate::sync::poison::{self, LockResult, MutexGuard, PoisonError, mutex};
3use crate::sys::sync as sys;
4use crate::time::{Duration, Instant};
5
6/// A type indicating whether a timed wait on a condition variable returned
7/// due to a time out or not.
8///
9/// It is returned by the [`wait_timeout`] method.
10///
11/// [`wait_timeout`]: Condvar::wait_timeout
12#[derive(Debug, PartialEq, Eq, Copy, Clone)]
13#[stable(feature = "wait_timeout", since = "1.5.0")]
14pub struct WaitTimeoutResult(bool);
15
16// FIXME(sync_nonpoison): `WaitTimeoutResult` is actually poisoning-agnostic, it seems.
17// Should we take advantage of this fact?
18impl WaitTimeoutResult {
19    /// Returns `true` if the wait was known to have timed out.
20    ///
21    /// # Examples
22    ///
23    /// This example spawns a thread which will sleep 20 milliseconds before
24    /// updating a boolean value and then notifying the condvar.
25    ///
26    /// The main thread will wait with a 10 millisecond timeout on the condvar
27    /// and will leave the loop upon timeout.
28    ///
29    /// ```
30    /// use std::sync::{Arc, Condvar, Mutex};
31    /// use std::thread;
32    /// use std::time::Duration;
33    ///
34    /// let pair = Arc::new((Mutex::new(false), Condvar::new()));
35    /// let pair2 = Arc::clone(&pair);
36    ///
37    /// # let handle =
38    /// thread::spawn(move || {
39    ///     let (lock, cvar) = &*pair2;
40    ///
41    ///     // Let's wait 20 milliseconds before notifying the condvar.
42    ///     thread::sleep(Duration::from_millis(20));
43    ///
44    ///     let mut started = lock.lock().unwrap();
45    ///     // We update the boolean value.
46    ///     *started = true;
47    ///     cvar.notify_one();
48    /// });
49    ///
50    /// // Wait for the thread to start up.
51    /// let (lock, cvar) = &*pair;
52    /// loop {
53    ///     // Let's put a timeout on the condvar's wait.
54    ///     let result = cvar.wait_timeout(lock.lock().unwrap(), Duration::from_millis(10)).unwrap();
55    ///     // 10 milliseconds have passed.
56    ///     if result.1.timed_out() {
57    ///         // timed out now and we can leave.
58    ///         break
59    ///     }
60    /// }
61    /// # // Prevent leaks for Miri.
62    /// # let _ = handle.join();
63    /// ```
64    #[must_use]
65    #[stable(feature = "wait_timeout", since = "1.5.0")]
66    pub fn timed_out(&self) -> bool {
67        self.0
68    }
69}
70
71/// A Condition Variable
72///
73/// Condition variables represent the ability to block a thread such that it
74/// consumes no CPU time while waiting for an event to occur. Condition
75/// variables are typically associated with a boolean predicate (a condition)
76/// and a mutex. The predicate is always verified inside of the mutex before
77/// determining that a thread must block.
78///
79/// Functions in this module will block the current **thread** of execution.
80/// Note that any attempt to use multiple mutexes on the same condition
81/// variable may result in a runtime panic.
82///
83/// # Examples
84///
85/// ```
86/// use std::sync::{Arc, Mutex, Condvar};
87/// use std::thread;
88///
89/// let pair = Arc::new((Mutex::new(false), Condvar::new()));
90/// let pair2 = Arc::clone(&pair);
91///
92/// // Inside of our lock, spawn a new thread, and then wait for it to start.
93/// thread::spawn(move || {
94///     let (lock, cvar) = &*pair2;
95///     let mut started = lock.lock().unwrap();
96///     *started = true;
97///     // We notify the condvar that the value has changed.
98///     cvar.notify_one();
99/// });
100///
101/// // Wait for the thread to start up.
102/// let (lock, cvar) = &*pair;
103/// let mut started = lock.lock().unwrap();
104/// while !*started {
105///     started = cvar.wait(started).unwrap();
106/// }
107/// ```
108#[stable(feature = "rust1", since = "1.0.0")]
109pub struct Condvar {
110    inner: sys::Condvar,
111}
112
113impl Condvar {
114    /// Creates a new condition variable which is ready to be waited on and
115    /// notified.
116    ///
117    /// # Examples
118    ///
119    /// ```
120    /// use std::sync::Condvar;
121    ///
122    /// let condvar = Condvar::new();
123    /// ```
124    #[stable(feature = "rust1", since = "1.0.0")]
125    #[rustc_const_stable(feature = "const_locks", since = "1.63.0")]
126    #[must_use]
127    #[inline]
128    pub const fn new() -> Condvar {
129        Condvar { inner: sys::Condvar::new() }
130    }
131
132    /// Blocks the current thread until this condition variable receives a
133    /// notification.
134    ///
135    /// This function will atomically unlock the mutex specified (represented by
136    /// `guard`) and block the current thread. This means that any calls
137    /// to [`notify_one`] or [`notify_all`] which happen logically after the
138    /// mutex is unlocked are candidates to wake this thread up. When this
139    /// function call returns, the lock specified will have been re-acquired.
140    ///
141    /// Note that this function is susceptible to spurious wakeups. Condition
142    /// variables normally have a boolean predicate associated with them, and
143    /// the predicate must always be checked each time this function returns to
144    /// protect against spurious wakeups.
145    ///
146    /// # Errors
147    ///
148    /// This function will return an error if the mutex being waited on is
149    /// poisoned when this thread re-acquires the lock. For more information,
150    /// see information about [poisoning] on the [`Mutex`] type.
151    ///
152    /// # Panics
153    ///
154    /// This function may [`panic!`] if it is used with more than one mutex
155    /// over time.
156    ///
157    /// [`notify_one`]: Self::notify_one
158    /// [`notify_all`]: Self::notify_all
159    /// [poisoning]: super::Mutex#poisoning
160    /// [`Mutex`]: super::Mutex
161    ///
162    /// # Examples
163    ///
164    /// ```
165    /// use std::sync::{Arc, Mutex, Condvar};
166    /// use std::thread;
167    ///
168    /// let pair = Arc::new((Mutex::new(false), Condvar::new()));
169    /// let pair2 = Arc::clone(&pair);
170    ///
171    /// thread::spawn(move || {
172    ///     let (lock, cvar) = &*pair2;
173    ///     let mut started = lock.lock().unwrap();
174    ///     *started = true;
175    ///     // We notify the condvar that the value has changed.
176    ///     cvar.notify_one();
177    /// });
178    ///
179    /// // Wait for the thread to start up.
180    /// let (lock, cvar) = &*pair;
181    /// let mut started = lock.lock().unwrap();
182    /// // As long as the value inside the `Mutex<bool>` is `false`, we wait.
183    /// while !*started {
184    ///     started = cvar.wait(started).unwrap();
185    /// }
186    /// ```
187    #[stable(feature = "rust1", since = "1.0.0")]
188    pub fn wait<'a, T>(&self, guard: MutexGuard<'a, T>) -> LockResult<MutexGuard<'a, T>> {
189        let poisoned = unsafe {
190            let lock = mutex::guard_lock(&guard);
191            self.inner.wait(lock);
192            mutex::guard_poison(&guard).get()
193        };
194        if poisoned { Err(PoisonError::new(guard)) } else { Ok(guard) }
195    }
196
197    /// Blocks the current thread until the provided condition becomes false.
198    ///
199    /// `condition` is checked immediately; if not met (returns `true`), this
200    /// will [`wait`] for the next notification then check again. This repeats
201    /// until `condition` returns `false`, in which case this function returns.
202    ///
203    /// This function will atomically unlock the mutex specified (represented by
204    /// `guard`) and block the current thread. This means that any calls
205    /// to [`notify_one`] or [`notify_all`] which happen logically after the
206    /// mutex is unlocked are candidates to wake this thread up. When this
207    /// function call returns, the lock specified will have been re-acquired.
208    ///
209    /// # Errors
210    ///
211    /// This function will return an error if the mutex being waited on is
212    /// poisoned when this thread re-acquires the lock. For more information,
213    /// see information about [poisoning] on the [`Mutex`] type.
214    ///
215    /// [`wait`]: Self::wait
216    /// [`notify_one`]: Self::notify_one
217    /// [`notify_all`]: Self::notify_all
218    /// [poisoning]: super::Mutex#poisoning
219    /// [`Mutex`]: super::Mutex
220    ///
221    /// # Examples
222    ///
223    /// ```
224    /// use std::sync::{Arc, Mutex, Condvar};
225    /// use std::thread;
226    ///
227    /// let pair = Arc::new((Mutex::new(true), Condvar::new()));
228    /// let pair2 = Arc::clone(&pair);
229    ///
230    /// thread::spawn(move || {
231    ///     let (lock, cvar) = &*pair2;
232    ///     let mut pending = lock.lock().unwrap();
233    ///     *pending = false;
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    /// // As long as the value inside the `Mutex<bool>` is `true`, we wait.
241    /// let _guard = cvar.wait_while(lock.lock().unwrap(), |pending| { *pending }).unwrap();
242    /// ```
243    #[stable(feature = "wait_until", since = "1.42.0")]
244    pub fn wait_while<'a, T, F>(
245        &self,
246        mut guard: MutexGuard<'a, T>,
247        mut condition: F,
248    ) -> LockResult<MutexGuard<'a, T>>
249    where
250        F: FnMut(&mut T) -> bool,
251    {
252        while condition(&mut *guard) {
253            guard = self.wait(guard)?;
254        }
255        Ok(guard)
256    }
257
258    /// Waits on this condition variable for a notification, timing out after a
259    /// specified duration.
260    ///
261    /// The semantics of this function are equivalent to [`wait`]
262    /// except that the thread will be blocked for roughly no longer
263    /// than `ms` milliseconds. This method should not be used for
264    /// precise timing due to anomalies such as preemption or platform
265    /// differences that might not cause the maximum amount of time
266    /// waited to be precisely `ms`.
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 boolean is `false` only if the timeout is known
273    /// to have elapsed.
274    ///
275    /// Like [`wait`], the lock specified will be re-acquired when this function
276    /// returns, regardless of whether the timeout elapsed or not.
277    ///
278    /// [`wait`]: Self::wait
279    ///
280    /// # Examples
281    ///
282    /// ```
283    /// use std::sync::{Arc, Mutex, Condvar};
284    /// use std::thread;
285    ///
286    /// let pair = Arc::new((Mutex::new(false), Condvar::new()));
287    /// let pair2 = Arc::clone(&pair);
288    ///
289    /// thread::spawn(move || {
290    ///     let (lock, cvar) = &*pair2;
291    ///     let mut started = lock.lock().unwrap();
292    ///     *started = true;
293    ///     // We notify the condvar that the value has changed.
294    ///     cvar.notify_one();
295    /// });
296    ///
297    /// // Wait for the thread to start up.
298    /// let (lock, cvar) = &*pair;
299    /// let mut started = lock.lock().unwrap();
300    /// // As long as the value inside the `Mutex<bool>` is `false`, we wait.
301    /// loop {
302    ///     let result = cvar.wait_timeout_ms(started, 10).unwrap();
303    ///     // 10 milliseconds have passed, or maybe the value changed!
304    ///     started = result.0;
305    ///     if *started == true {
306    ///         // We received the notification and the value has been updated, we can leave.
307    ///         break
308    ///     }
309    /// }
310    /// ```
311    #[stable(feature = "rust1", since = "1.0.0")]
312    #[deprecated(since = "1.6.0", note = "replaced by `std::sync::Condvar::wait_timeout`")]
313    pub fn wait_timeout_ms<'a, T>(
314        &self,
315        guard: MutexGuard<'a, T>,
316        ms: u32,
317    ) -> LockResult<(MutexGuard<'a, T>, bool)> {
318        let res = self.wait_timeout(guard, Duration::from_millis(ms as u64));
319        poison::map_result(res, |(a, b)| (a, !b.timed_out()))
320    }
321
322    /// Waits on this condition variable for a notification, timing out after a
323    /// specified duration.
324    ///
325    /// The semantics of this function are equivalent to [`wait`] except that
326    /// the thread will be blocked for roughly no longer than `dur`. This
327    /// method should not be used for precise timing due to anomalies such as
328    /// preemption or platform differences that might not cause the maximum
329    /// amount of time waited to be precisely `dur`.
330    ///
331    /// Note that the best effort is made to ensure that the time waited is
332    /// measured with a monotonic clock, and not affected by the changes made to
333    /// the system time. This function is susceptible to spurious wakeups.
334    /// Condition variables normally have a boolean predicate associated with
335    /// them, and the predicate must always be checked each time this function
336    /// returns to protect against spurious wakeups. Additionally, it is
337    /// typically desirable for the timeout to not exceed some duration in
338    /// spite of spurious wakes, thus the sleep-duration is decremented by the
339    /// amount slept. Alternatively, use the `wait_timeout_while` method
340    /// to wait with a timeout while a predicate is true.
341    ///
342    /// The returned [`WaitTimeoutResult`] value indicates if the timeout is
343    /// known to have elapsed.
344    ///
345    /// Like [`wait`], the lock specified will be re-acquired when this function
346    /// returns, regardless of whether the timeout elapsed or not.
347    ///
348    /// [`wait`]: Self::wait
349    /// [`wait_timeout_while`]: Self::wait_timeout_while
350    ///
351    /// # Examples
352    ///
353    /// ```
354    /// use std::sync::{Arc, Mutex, Condvar};
355    /// use std::thread;
356    /// use std::time::Duration;
357    ///
358    /// let pair = Arc::new((Mutex::new(false), Condvar::new()));
359    /// let pair2 = Arc::clone(&pair);
360    ///
361    /// thread::spawn(move || {
362    ///     let (lock, cvar) = &*pair2;
363    ///     let mut started = lock.lock().unwrap();
364    ///     *started = true;
365    ///     // We notify the condvar that the value has changed.
366    ///     cvar.notify_one();
367    /// });
368    ///
369    /// // wait for the thread to start up
370    /// let (lock, cvar) = &*pair;
371    /// let mut started = lock.lock().unwrap();
372    /// // as long as the value inside the `Mutex<bool>` is `false`, we wait
373    /// loop {
374    ///     let result = cvar.wait_timeout(started, Duration::from_millis(10)).unwrap();
375    ///     // 10 milliseconds have passed, or maybe the value changed!
376    ///     started = result.0;
377    ///     if *started == true {
378    ///         // We received the notification and the value has been updated, we can leave.
379    ///         break
380    ///     }
381    /// }
382    /// ```
383    #[stable(feature = "wait_timeout", since = "1.5.0")]
384    pub fn wait_timeout<'a, T>(
385        &self,
386        guard: MutexGuard<'a, T>,
387        dur: Duration,
388    ) -> LockResult<(MutexGuard<'a, T>, WaitTimeoutResult)> {
389        let (poisoned, result) = unsafe {
390            let lock = mutex::guard_lock(&guard);
391            let success = self.inner.wait_timeout(lock, dur);
392            (mutex::guard_poison(&guard).get(), WaitTimeoutResult(!success))
393        };
394        if poisoned { Err(PoisonError::new((guard, result))) } else { Ok((guard, result)) }
395    }
396
397    /// Waits on this condition variable for a notification, timing out after a
398    /// specified duration.
399    ///
400    /// The semantics of this function are equivalent to [`wait_while`] except
401    /// that the thread will be blocked for roughly no longer than `dur`. This
402    /// method should not be used for precise timing due to anomalies such as
403    /// preemption or platform differences that might not cause the maximum
404    /// amount of time waited to be precisely `dur`.
405    ///
406    /// Note that the best effort is made to ensure that the time waited is
407    /// measured with a monotonic clock, and not affected by the changes made to
408    /// the system time.
409    ///
410    /// The returned [`WaitTimeoutResult`] value indicates if the timeout is
411    /// known to have elapsed without the condition being met.
412    ///
413    /// Like [`wait_while`], the lock specified will be re-acquired when this
414    /// function returns, regardless of whether the timeout elapsed or not.
415    ///
416    /// [`wait_while`]: Self::wait_while
417    /// [`wait_timeout`]: Self::wait_timeout
418    ///
419    /// # Examples
420    ///
421    /// ```
422    /// use std::sync::{Arc, Mutex, Condvar};
423    /// use std::thread;
424    /// use std::time::Duration;
425    ///
426    /// let pair = Arc::new((Mutex::new(true), Condvar::new()));
427    /// let pair2 = Arc::clone(&pair);
428    ///
429    /// thread::spawn(move || {
430    ///     let (lock, cvar) = &*pair2;
431    ///     let mut pending = lock.lock().unwrap();
432    ///     *pending = false;
433    ///     // We notify the condvar that the value has changed.
434    ///     cvar.notify_one();
435    /// });
436    ///
437    /// // wait for the thread to start up
438    /// let (lock, cvar) = &*pair;
439    /// let result = cvar.wait_timeout_while(
440    ///     lock.lock().unwrap(),
441    ///     Duration::from_millis(100),
442    ///     |&mut pending| pending,
443    /// ).unwrap();
444    /// if result.1.timed_out() {
445    ///     // timed-out without the condition ever evaluating to false.
446    /// }
447    /// // access the locked mutex via result.0
448    /// ```
449    #[stable(feature = "wait_timeout_until", since = "1.42.0")]
450    pub fn wait_timeout_while<'a, T, F>(
451        &self,
452        mut guard: MutexGuard<'a, T>,
453        dur: Duration,
454        mut condition: F,
455    ) -> LockResult<(MutexGuard<'a, T>, WaitTimeoutResult)>
456    where
457        F: FnMut(&mut T) -> bool,
458    {
459        let start = Instant::now();
460        loop {
461            if !condition(&mut *guard) {
462                return Ok((guard, WaitTimeoutResult(false)));
463            }
464            let timeout = match dur.checked_sub(start.elapsed()) {
465                Some(timeout) => timeout,
466                None => return Ok((guard, WaitTimeoutResult(true))),
467            };
468            guard = self.wait_timeout(guard, timeout)?.0;
469        }
470    }
471
472    /// Wakes up one blocked thread on this condvar.
473    ///
474    /// If there is a blocked thread on this condition variable, then it will
475    /// be woken up from its call to [`wait`] or [`wait_timeout`]. Calls to
476    /// `notify_one` are not buffered in any way.
477    ///
478    /// To wake up all threads, see [`notify_all`].
479    ///
480    /// [`wait`]: Self::wait
481    /// [`wait_timeout`]: Self::wait_timeout
482    /// [`notify_all`]: Self::notify_all
483    ///
484    /// # Examples
485    ///
486    /// ```
487    /// use std::sync::{Arc, Mutex, Condvar};
488    /// use std::thread;
489    ///
490    /// let pair = Arc::new((Mutex::new(false), Condvar::new()));
491    /// let pair2 = Arc::clone(&pair);
492    ///
493    /// thread::spawn(move || {
494    ///     let (lock, cvar) = &*pair2;
495    ///     let mut started = lock.lock().unwrap();
496    ///     *started = true;
497    ///     // We notify the condvar that the value has changed.
498    ///     cvar.notify_one();
499    /// });
500    ///
501    /// // Wait for the thread to start up.
502    /// let (lock, cvar) = &*pair;
503    /// let mut started = lock.lock().unwrap();
504    /// // As long as the value inside the `Mutex<bool>` is `false`, we wait.
505    /// while !*started {
506    ///     started = cvar.wait(started).unwrap();
507    /// }
508    /// ```
509    #[stable(feature = "rust1", since = "1.0.0")]
510    pub fn notify_one(&self) {
511        self.inner.notify_one()
512    }
513
514    /// Wakes up all blocked threads on this condvar.
515    ///
516    /// This method will ensure that any current waiters on the condition
517    /// variable are awoken. Calls to `notify_all()` are not buffered in any
518    /// way.
519    ///
520    /// To wake up only one thread, see [`notify_one`].
521    ///
522    /// [`notify_one`]: Self::notify_one
523    ///
524    /// # Examples
525    ///
526    /// ```
527    /// use std::sync::{Arc, Mutex, Condvar};
528    /// use std::thread;
529    ///
530    /// let pair = Arc::new((Mutex::new(false), Condvar::new()));
531    /// let pair2 = Arc::clone(&pair);
532    ///
533    /// thread::spawn(move || {
534    ///     let (lock, cvar) = &*pair2;
535    ///     let mut started = lock.lock().unwrap();
536    ///     *started = true;
537    ///     // We notify the condvar that the value has changed.
538    ///     cvar.notify_all();
539    /// });
540    ///
541    /// // Wait for the thread to start up.
542    /// let (lock, cvar) = &*pair;
543    /// let mut started = lock.lock().unwrap();
544    /// // As long as the value inside the `Mutex<bool>` is `false`, we wait.
545    /// while !*started {
546    ///     started = cvar.wait(started).unwrap();
547    /// }
548    /// ```
549    #[stable(feature = "rust1", since = "1.0.0")]
550    pub fn notify_all(&self) {
551        self.inner.notify_all()
552    }
553}
554
555#[stable(feature = "std_debug", since = "1.16.0")]
556impl fmt::Debug for Condvar {
557    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
558        f.debug_struct("Condvar").finish_non_exhaustive()
559    }
560}
561
562#[stable(feature = "condvar_default", since = "1.10.0")]
563impl Default for Condvar {
564    /// Creates a `Condvar` which is ready to be waited on and notified.
565    fn default() -> Condvar {
566        Condvar::new()
567    }
568}
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy