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}