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. Additionally, it is
202 /// typically desirable for the timeout to not exceed some duration in
203 /// spite of spurious wakes, thus the sleep-duration is decremented by the
204 /// amount slept. Alternatively, use the `wait_timeout_while` method
205 /// to wait with a timeout while a predicate is true.
206 ///
207 /// The returned [`WaitTimeoutResult`] value indicates if the timeout is
208 /// known to have elapsed.
209 ///
210 /// Like [`wait`], the lock specified will be re-acquired when this function
211 /// returns, regardless of whether the timeout elapsed or not.
212 ///
213 /// [`wait`]: Self::wait
214 /// [`wait_timeout_while`]: Self::wait_timeout_while
215 ///
216 /// # Examples
217 ///
218 /// ```
219 /// #![feature(nonpoison_mutex)]
220 /// #![feature(nonpoison_condvar)]
221 ///
222 /// use std::sync::nonpoison::{Mutex, Condvar};
223 /// use std::sync::Arc;
224 /// use std::thread;
225 /// use std::time::Duration;
226 ///
227 /// let pair = Arc::new((Mutex::new(false), Condvar::new()));
228 /// let pair2 = Arc::clone(&pair);
229 ///
230 /// thread::spawn(move || {
231 /// let (lock, cvar) = &*pair2;
232 /// let mut started = lock.lock();
233 /// *started = true;
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 /// let mut started = lock.lock();
241 /// // as long as the value inside the `Mutex<bool>` is `false`, we wait
242 /// loop {
243 /// let result = cvar.wait_timeout(started, Duration::from_millis(10));
244 /// // 10 milliseconds have passed, or maybe the value changed!
245 /// started = result.0;
246 /// if *started == true {
247 /// // We received the notification and the value has been updated, we can leave.
248 /// break
249 /// }
250 /// }
251 /// ```
252 #[unstable(feature = "nonpoison_condvar", issue = "134645")]
253 pub fn wait_timeout<'a, T>(
254 &self,
255 guard: MutexGuard<'a, T>,
256 dur: Duration,
257 ) -> (MutexGuard<'a, T>, WaitTimeoutResult) {
258 let success = unsafe {
259 let lock = mutex::guard_lock(&guard);
260 self.inner.wait_timeout(lock, dur)
261 };
262 (guard, WaitTimeoutResult(!success))
263 }
264
265 /// Waits on this condition variable for a notification, timing out after a
266 /// specified duration.
267 ///
268 /// The semantics of this function are equivalent to [`wait_while`] except
269 /// that the thread will be blocked for roughly no longer than `dur`. This
270 /// method should not be used for precise timing due to anomalies such as
271 /// preemption or platform differences that might not cause the maximum
272 /// amount of time waited to be precisely `dur`.
273 ///
274 /// Note that the best effort is made to ensure that the time waited is
275 /// measured with a monotonic clock, and not affected by the changes made to
276 /// the system time.
277 ///
278 /// The returned [`WaitTimeoutResult`] value indicates if the timeout is
279 /// known to have elapsed without the condition being met.
280 ///
281 /// Like [`wait_while`], the lock specified will be re-acquired when this
282 /// function returns, regardless of whether the timeout elapsed or not.
283 ///
284 /// [`wait_while`]: Self::wait_while
285 /// [`wait_timeout`]: Self::wait_timeout
286 ///
287 /// # Examples
288 ///
289 /// ```
290 /// #![feature(nonpoison_mutex)]
291 /// #![feature(nonpoison_condvar)]
292 ///
293 /// use std::sync::nonpoison::{Mutex, Condvar};
294 /// use std::sync::Arc;
295 /// use std::thread;
296 /// use std::time::Duration;
297 ///
298 /// let pair = Arc::new((Mutex::new(true), Condvar::new()));
299 /// let pair2 = Arc::clone(&pair);
300 ///
301 /// thread::spawn(move || {
302 /// let (lock, cvar) = &*pair2;
303 /// let mut pending = lock.lock();
304 /// *pending = false;
305 /// // We notify the condvar that the value has changed.
306 /// cvar.notify_one();
307 /// });
308 ///
309 /// // wait for the thread to start up
310 /// let (lock, cvar) = &*pair;
311 /// let result = cvar.wait_timeout_while(
312 /// lock.lock(),
313 /// Duration::from_millis(100),
314 /// |&mut pending| pending,
315 /// );
316 /// if result.1.timed_out() {
317 /// // timed-out without the condition ever evaluating to false.
318 /// }
319 /// // access the locked mutex via result.0
320 /// ```
321 #[unstable(feature = "nonpoison_condvar", issue = "134645")]
322 pub fn wait_timeout_while<'a, T, F>(
323 &self,
324 mut guard: MutexGuard<'a, T>,
325 dur: Duration,
326 mut condition: F,
327 ) -> (MutexGuard<'a, T>, WaitTimeoutResult)
328 where
329 F: FnMut(&mut T) -> bool,
330 {
331 let start = Instant::now();
332 loop {
333 if !condition(&mut *guard) {
334 return (guard, WaitTimeoutResult(false));
335 }
336 let timeout = match dur.checked_sub(start.elapsed()) {
337 Some(timeout) => timeout,
338 None => return (guard, WaitTimeoutResult(true)),
339 };
340 guard = self.wait_timeout(guard, timeout).0;
341 }
342 }
343
344 /// Wakes up one blocked thread on this condvar.
345 ///
346 /// If there is a blocked thread on this condition variable, then it will
347 /// be woken up from its call to [`wait`] or [`wait_timeout`]. Calls to
348 /// `notify_one` are not buffered in any way.
349 ///
350 /// To wake up all threads, see [`notify_all`].
351 ///
352 /// [`wait`]: Self::wait
353 /// [`wait_timeout`]: Self::wait_timeout
354 /// [`notify_all`]: Self::notify_all
355 ///
356 /// # Examples
357 ///
358 /// ```
359 /// #![feature(nonpoison_mutex)]
360 /// #![feature(nonpoison_condvar)]
361 ///
362 /// use std::sync::nonpoison::{Mutex, Condvar};
363 /// use std::sync::Arc;
364 /// use std::thread;
365 ///
366 /// let pair = Arc::new((Mutex::new(false), Condvar::new()));
367 /// let pair2 = Arc::clone(&pair);
368 ///
369 /// thread::spawn(move || {
370 /// let (lock, cvar) = &*pair2;
371 /// let mut started = lock.lock();
372 /// *started = true;
373 /// // We notify the condvar that the value has changed.
374 /// cvar.notify_one();
375 /// });
376 ///
377 /// // Wait for the thread to start up.
378 /// let (lock, cvar) = &*pair;
379 /// let mut started = lock.lock();
380 /// // As long as the value inside the `Mutex<bool>` is `false`, we wait.
381 /// while !*started {
382 /// started = cvar.wait(started);
383 /// }
384 /// ```
385 #[unstable(feature = "nonpoison_condvar", issue = "134645")]
386 pub fn notify_one(&self) {
387 self.inner.notify_one()
388 }
389
390 /// Wakes up all blocked threads on this condvar.
391 ///
392 /// This method will ensure that any current waiters on the condition
393 /// variable are awoken. Calls to `notify_all()` are not buffered in any
394 /// way.
395 ///
396 /// To wake up only one thread, see [`notify_one`].
397 ///
398 /// [`notify_one`]: Self::notify_one
399 ///
400 /// # Examples
401 ///
402 /// ```
403 /// #![feature(nonpoison_mutex)]
404 /// #![feature(nonpoison_condvar)]
405 ///
406 /// use std::sync::nonpoison::{Mutex, Condvar};
407 /// use std::sync::Arc;
408 /// use std::thread;
409 ///
410 /// let pair = Arc::new((Mutex::new(false), Condvar::new()));
411 /// let pair2 = Arc::clone(&pair);
412 ///
413 /// thread::spawn(move || {
414 /// let (lock, cvar) = &*pair2;
415 /// let mut started = lock.lock();
416 /// *started = true;
417 /// // We notify the condvar that the value has changed.
418 /// cvar.notify_all();
419 /// });
420 ///
421 /// // Wait for the thread to start up.
422 /// let (lock, cvar) = &*pair;
423 /// let mut started = lock.lock();
424 /// // As long as the value inside the `Mutex<bool>` is `false`, we wait.
425 /// while !*started {
426 /// started = cvar.wait(started);
427 /// }
428 /// ```
429 #[unstable(feature = "nonpoison_condvar", issue = "134645")]
430 pub fn notify_all(&self) {
431 self.inner.notify_all()
432 }
433}
434
435#[unstable(feature = "nonpoison_condvar", issue = "134645")]
436impl fmt::Debug for Condvar {
437 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
438 f.debug_struct("Condvar").finish_non_exhaustive()
439 }
440}
441
442#[unstable(feature = "nonpoison_condvar", issue = "134645")]
443impl Default for Condvar {
444 /// Creates a `Condvar` which is ready to be waited on and notified.
445 fn default() -> Condvar {
446 Condvar::new()
447 }
448}