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}