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}