Mbed OS Reference
Loading...
Searching...
No Matches
ConditionVariable.h
1/* Mbed Microcontroller Library
2 * Copyright (c) 2017-2019 ARM Limited
3 * SPDX-License-Identifier: MIT
4 *
5 * Permission is hereby granted, free of charge, to any person obtaining a copy
6 * of this software and associated documentation files (the "Software"), to deal
7 * in the Software without restriction, including without limitation the rights
8 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 * copies of the Software, and to permit persons to whom the Software is
10 * furnished to do so, subject to the following conditions:
11 *
12 * The above copyright notice and this permission notice shall be included in
13 * all copies or substantial portions of the Software.
14 *
15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 * SOFTWARE.
22 */
23#ifndef CONDITIONVARIABLE_H
24#define CONDITIONVARIABLE_H
25
26#include <stdint.h>
27#include <utility>
28#include "rtos/mbed_rtos_types.h"
29#include "rtos/Mutex.h"
30#include "rtos/Semaphore.h"
31#include "rtos/Kernel.h"
32
33#include "platform/NonCopyable.h"
34
35#if MBED_CONF_RTOS_PRESENT || defined(DOXYGEN_ONLY)
36
37namespace rtos {
38/** \addtogroup rtos-public-api */
39/** @{*/
40
41enum class cv_status {
42 no_timeout,
43 timeout
44};
45
46struct Waiter;
47/**
48 * \defgroup rtos_ConditionVariable ConditionVariable class
49 * @{
50 */
51
52/** The ConditionVariable class is a synchronization primitive that allows
53 * threads to wait until a particular condition occurs.
54 *
55 * Use the condition variable in conjunction with a mutex to safely wait for
56 * or notify waiters of condition changes to a resource accessible by multiple
57 * threads.
58 *
59 * The thread that intends to wait on a ConditionVariable must:
60 * - Acquire a lock on a mutex.
61 * - Execute `wait`, `wait_for` or `wait_until`. While the thread is waiting,
62 * the mutex is unlocked.
63 * - When the condition variable has been notified, or in the case of `wait_for`
64 * and `wait_until` the timeout expires, the thread is awakened.
65 *
66 * The thread that intends to notify a ConditionVariable must:
67 * - Acquire a lock on the mutex used to construct the condition variable.
68 * - Execute `notify_one` or `notify_all` on the condition variable.
69 *
70 * All threads waiting on the condition variable wake when
71 * `ConditionVariable::notify_all` is called.
72 * At least one thread waiting on the condition variable wakes
73 * when `ConditionVariable::notify_one` is called.
74 *
75 * While a thread is waiting for notification of a
76 * ConditionVariable, it releases the lock held on the mutex.
77 * The ConditionVariable reacquires the mutex lock before exiting the wait
78 * function.
79 *
80 * #### Unspecified behavior
81 * - The thread that is unblocked on `ConditionVariable::notify_one` is
82 * unspecified if there are multiple waiters.
83 * - When `ConditionVariable::notify_one` or `ConditionVariable::notify_all` is
84 * called and there are one or more waiters, and one or more threads
85 * attempting to acquire the condition variable's mutex, the order in which the mutex is
86 * acquired is unspecified.
87 * - Spurious notifications (not triggered by the application) can occur.
88 *
89 * #### Undefined behavior
90 * - Calling wait if the mutex is not locked by the current thread is undefined
91 * behavior.
92 * - The order in which waiting threads acquire the condition variable's
93 * mutex after `ConditionVariable::notify_all` is called is undefined.
94 * - The behavior of `ConditionVariable::wait` and `ConditionVariable::wait_for`
95 * is undefined if the condition variable's mutex is locked more than once by
96 * the calling thread.
97 *
98 * @note Synchronization level: Thread safe
99 *
100 * @note Bare metal profile: This class is not supported.
101 *
102 * Example:
103 *
104 * @code
105 * #include "mbed.h"
106 *
107 * Mutex mutex;
108 * ConditionVariable cv(mutex);
109 *
110 * // These variables are protected by locking the mutex.
111 * uint32_t work_count = 0;
112 * bool done = false;
113 *
114 * void worker_thread()
115 * {
116 * // Acquire lock on mutex before accessing protected variables and waiting.
117 * mutex.lock();
118 *
119 * while (done == false) {
120 * printf("Worker thread: Count: %lu\r\n", work_count);
121 *
122 * // Wait for main thread to notify the condition variable.
123 * printf("Worker thread: Waiting\r\n");
124 * cv.wait();
125 * }
126 *
127 * printf("Worker: Exiting\r\n");
128 *
129 * // The condition variable acquires the lock when exiting the `wait` function.
130 * // Unlock mutex when exiting the thread.
131 * mutex.unlock();
132 * }
133 *
134 * int main()
135 * {
136 * Thread thread;
137 * thread.start(worker_thread);
138 *
139 * for (int i = 0; i < 5; i++) {
140 * // Acquire lock on mutex before modifying variables and notifying.
141 * mutex.lock();
142 *
143 * // Change count and notify waiters.
144 * work_count++;
145 * printf("Main thread: Set count to: %lu\r\n", work_count);
146 * printf("Main thread: Notifying worker thread\r\n");
147 * cv.notify_all();
148 *
149 * // Mutex must be unlocked before the worker thread can acquire it.
150 * mutex.unlock();
151 *
152 * ThisThread::sleep_for(1000);
153 * }
154 *
155 * // Change done and notify waiters of this.
156 * mutex.lock();
157 * done = true;
158 * cv.notify_all();
159 * mutex.unlock();
160 *
161 * thread.join();
162 *
163 * printf("Main: Exiting\r\n");
164 * }
165 * @endcode
166 */
167
168class ConditionVariable : private mbed::NonCopyable<ConditionVariable> {
169public:
170 /** Create and initialize a ConditionVariable object.
171 *
172 * @note You cannot call this function from ISR context.
173 */
175
176 /** Wait for a notification.
177 *
178 * Wait causes the current thread to block until the condition variable
179 * receives a notification from another thread.
180 *
181 * @note - The thread calling this function must be the owner of the
182 * ConditionVariable's mutex, and it must be locked exactly once.
183 *
184 * @note - Spurious notifications can occur, so the caller of this API
185 * should check to make sure the condition the caller is waiting on has
186 * been met.
187 *
188 * @note - The current thread releases the mutex while inside the wait
189 * function and reacquires it upon exiting the function.
190 *
191 * Example:
192 * @code
193 * mutex.lock();
194 *
195 * while (!condition_met) {
196 * cond.wait();
197 * }
198 *
199 * function_to_handle_condition();
200 *
201 * mutex.unlock();
202 * @endcode
203 *
204 * @note You cannot call this function from ISR context.
205 */
206 void wait();
207
208 /** Wait for a predicate.
209 *
210 * Wait causes the current thread to block until the predicate is
211 * true.
212 *
213 * @param pred A function-like object such that `pred()` is convertible to bool
214 *
215 * @note - The thread calling this function must be the owner of the
216 * ConditionVariable's mutex, and it must be locked exactly once.
217 *
218 * @note - The current thread releases the mutex while inside the wait
219 * function and reacquires it upon exiting the function.
220 *
221 * Example:
222 * @code
223 * extern bool data_available();
224 *
225 * mutex.lock();
226 *
227 * cond.wait(data_available);
228 *
229 * function_to_handle_data();
230 *
231 * mutex.unlock();
232 * @endcode
233 *
234 * @note You cannot call this function from ISR context.
235 */
236 template <typename Predicate>
237 void wait(Predicate pred)
238 {
239 while (!pred()) {
240 wait();
241 }
242 }
243
244
245 /** Wait for a notification until the specified time.
246 *
247 * Wait until causes the current thread to block until the condition
248 * variable is notified, or a specific time given by millisec parameter is
249 * reached.
250 *
251 * @param millisec Absolute end time referenced to `Kernel::get_ms_count()`
252 * @return `true` if a timeout occurred, `false` otherwise.
253 *
254 * @note - The thread calling this function must be the owner of the
255 * ConditionVariable's mutex, and it must be locked exactly once.
256 *
257 * @note - Spurious notifications can occur, so the caller of this API
258 * should check to make sure the condition the caller is waiting on has
259 * been met.
260 *
261 * @note - The current thread releases the lock while inside the wait
262 * function and reacquires it upon exiting the function.
263 *
264 * Example:
265 * @code
266 * mutex.lock();
267 * uint64_t end_time = Kernel::get_ms_count() + COND_WAIT_TIMEOUT;
268 *
269 * while (!condition_met) {
270 * if (cond.wait_until(end_time)) {
271 * break;
272 * }
273 * }
274 *
275 * if (condition_met) {
276 * function_to_handle_condition();
277 * }
278 *
279 * mutex.unlock();
280 * @endcode
281 *
282 * @note You cannot call this function from ISR context.
283 * @deprecated Pass a chrono time_point, not an integer millisecond count. For example use `Kernel::Clock::now() + 5s`
284 * rather than `Kernel::get_ms_count() + 5000`.
285 */
286 MBED_DEPRECATED_SINCE("mbed-os-6.0.0", "Pass a chrono time_point, not an integer millisecond count. For example use `Kernel::Clock::now() + 5s` rather than `Kernel::get_ms_count() + 5000`.")
287 bool wait_until(uint64_t millisec);
288
289 /** Wait for a notification until the specified time.
290 *
291 * Wait until causes the current thread to block until the condition
292 * variable is notified, or a specific time given by millisec parameter is
293 * reached.
294 *
295 * @param abs_time Absolute end time referenced to `Kernel::Clock`
296 * @return `cv_status::timeout` if a timeout occurred, `cv_status::no_timeout` otherwise.
297 *
298 * @note - The thread calling this function must be the owner of the
299 * ConditionVariable's mutex, and it must be locked exactly once.
300 *
301 * @note - Spurious notifications can occur, so the caller of this API
302 * should check to make sure the condition the caller is waiting on has
303 * been met.
304 *
305 * @note - The current thread releases the lock while inside the wait
306 * function and reacquires it upon exiting the function.
307 *
308 * Example:
309 * @code
310 * mutex.lock();
311 * Kernel::Clock::time_point end_time = Kernel::Clock::now() + 2s;
312 *
313 * while (!condition_met) {
314 * if (cond.wait_until(end_time) == cv_status::timeout) {
315 * break;
316 * }
317 * }
318 *
319 * if (condition_met) {
320 * function_to_handle_condition();
321 * }
322 *
323 * mutex.unlock();
324 * @endcode
325 *
326 * @note You cannot call this function from ISR context.
327 */
328 cv_status wait_until(Kernel::Clock::time_point abs_time);
329
330 /** Wait for a predicate until the specified time.
331 *
332 * Wait until causes the current thread to block until the predicate is true,
333 * or a specific time given by abs_time parameter is reached.
334 *
335 * @param abs_time Absolute end time referenced to `Kernel::Clock`
336 * @param pred A function-like object such that `pred()` is convertible to bool
337 * @return The state of the predicate
338 *
339 * @note - The thread calling this function must be the owner of the
340 * ConditionVariable's mutex, and it must be locked exactly once.
341 *
342 * @note - The current thread releases the mutex while inside the wait
343 * function and reacquires it upon exiting the function.
344 *
345 * Example:
346 * @code
347 * extern bool data_available();
348 *
349 * mutex.lock();
350 *
351 * if (cond.wait_until(Kernel::Clock::now() + 2s, data_available)) {
352 * function_to_handle_data();
353 * }
354 *
355 * mutex.unlock();
356 * @endcode
357 *
358 * @note You cannot call this function from ISR context.
359 */
360 template <class Predicate>
361 bool wait_until(Kernel::Clock::time_point abs_time, Predicate pred)
362 {
363 while (!pred()) {
364 if (wait_until(abs_time) == cv_status::timeout) {
365 return pred();
366 }
367 }
368 return true;
369 }
370
371 /** Wait for a notification or timeout.
372 *
373 * `Wait for` causes the current thread to block until the condition
374 * variable receives a notification from another thread, or the timeout
375 * specified by the millisec parameter is reached.
376 *
377 * @param millisec Timeout value or osWaitForever in case of no timeout.
378 * @return `true` if a timeout occurred, `false` otherwise.
379 *
380 * @note - The thread calling this function must be the owner of the
381 * ConditionVariable's mutex, and it must be locked exactly once.
382 *
383 * @note - Spurious notifications can occur, so the caller of this API
384 * should check to make sure the condition the caller is waiting on has
385 * been met.
386 *
387 * @note - The current thread releases the lock while inside the wait
388 * function and reacquire it upon exiting the function.
389 *
390 * Example:
391 * @code
392 * mutex.lock();
393 *
394 * while (!condition_met) {
395 * cond.wait_for(MAX_SLEEP_TIME);
396 * if (!condition_met) {
397 * do_other_work_while_condition_false();
398 * }
399 * }
400 *
401 * if (condition_met) {
402 * function_to_handle_condition();
403 * }
404 *
405 * mutex.unlock();
406 * @endcode
407 *
408 * @note You cannot call this function from ISR context.
409 * @deprecated Pass a chrono duration, not an integer millisecond count. For example use `5s` rather than `5000`.
410 */
411 MBED_DEPRECATED_SINCE("mbed-os-6.0.0", "Pass a chrono duration, not an integer millisecond count. For example use `5s` rather than `5000`.")
412 bool wait_for(uint32_t millisec);
413
414 /** Wait for a notification or timeout.
415 *
416 * `Wait for` causes the current thread to block until the condition
417 * variable receives a notification from another thread, or the timeout
418 * specified by the millisec parameter is reached.
419 *
420 * @param rel_time Timeout value.
421 * @return `cv_status::timeout` if a timeout occurred, `cv_status::no_timeout` otherwise.
422 *
423 * @note - The thread calling this function must be the owner of the
424 * ConditionVariable's mutex, and it must be locked exactly once.
425 *
426 * @note - Spurious notifications can occur, so the caller of this API
427 * should check to make sure the condition the caller is waiting on has
428 * been met.
429 *
430 * @note - The current thread releases the lock while inside the wait
431 * function and reacquire it upon exiting the function.
432 *
433 * Example:
434 * @code
435 * mutex.lock();
436 *
437 * while (!condition_met) {
438 * cond.wait_for(MAX_SLEEP_TIME);
439 * if (!condition_met) {
440 * do_other_work_while_condition_false();
441 * }
442 * }
443 *
444 * if (condition_met) {
445 * function_to_handle_condition();
446 * }
447 *
448 * mutex.unlock();
449 * @endcode
450 *
451 * @note You cannot call this function from ISR context.
452 */
453 cv_status wait_for(Kernel::Clock::duration_u32 rel_time);
454
455 /** Wait for a predicate or timeout.
456 *
457 * `Wait for` causes the current thread to block until the predicate
458 * is true, or the timeout specified by the rel_time parameter is reached.
459 *
460 * @param rel_time Timeout value.
461 * @param pred a function-like object such that `pred()` is convertible to bool
462 * @return The state of the predicate
463 *
464 * @note - The thread calling this function must be the owner of the
465 * ConditionVariable's mutex, and it must be locked exactly once.
466 *
467 * @note - The current thread releases the mutex while inside the wait
468 * function and reacquire it upon exiting the function.
469 *
470 * Example:
471 * @code
472 * extern bool data_available();
473 *
474 * mutex.lock();
475 *
476 * if (cond.wait_for(2s, data_available)) {
477 * function_to_handle_data();
478 * }
479 *
480 * mutex.unlock();
481 * @endcode
482 *
483 * @note You cannot call this function from ISR context.
484 */
485 template <class Predicate>
486 bool wait_for(Kernel::Clock::duration rel_time, Predicate pred)
487 {
488 return wait_until(Kernel::Clock::now() + rel_time, std::move(pred));
489 }
490
491 /** Notify one waiter on this condition variable that a condition changed.
492 *
493 * This function unblocks one of the threads waiting for the condition
494 * variable.
495 *
496 * @note - The thread calling this function must be the owner of the
497 * ConditionVariable's mutex.
498 *
499 * @note - The thread that is unblocked on ConditionVariable::notify_one is
500 * undefined if there are multiple waiters.
501 *
502 * @note You cannot call this function from ISR context.
503 */
505
506 /** Notify all waiters on this condition variable that a condition changed.
507 *
508 * This function unblocks all of the threads waiting for the condition
509 * variable.
510 *
511 * @note - The thread calling this function must be the owner of the
512 * ConditionVariable's mutex.
513 *
514 * @note - If there are one or more waiters and one or more threads
515 * attempting to acquire the condition variable's mutex the order in which
516 * the mutex is acquired is undefined.
517 *
518 * @note You cannot call this function from ISR context.
519 */
521
522 /** ConditionVariable destructor.
523 *
524 * @note You cannot call this function from ISR context.
525 */
527
528#if !defined(DOXYGEN_ONLY)
529protected:
530 struct Waiter {
531 Waiter();
532 Semaphore sem;
533 Waiter *prev;
534 Waiter *next;
535 bool in_list;
536 };
537
538 static void _add_wait_list(Waiter **wait_list, Waiter *waiter);
539 static void _remove_wait_list(Waiter **wait_list, Waiter *waiter);
540 Mutex &_mutex;
541 Waiter *_wait_list;
542#endif // !defined(DOXYGEN_ONLY)
543};
544
545/** @}*/
546/** @}*/
547} // namespace rtos
548#endif
549
550#endif
Prevents generation of copy constructor and copy assignment operator in derived classes.
Definition: NonCopyable.h:162
The ConditionVariable class is a synchronization primitive that allows threads to wait until a partic...
~ConditionVariable()
ConditionVariable destructor.
bool wait_for(uint32_t millisec)
Wait for a notification or timeout.
void wait(Predicate pred)
Wait for a predicate.
ConditionVariable(Mutex &mutex)
Create and initialize a ConditionVariable object.
void notify_one()
Notify one waiter on this condition variable that a condition changed.
void wait()
Wait for a notification.
void notify_all()
Notify all waiters on this condition variable that a condition changed.
bool wait_until(uint64_t millisec)
Wait for a notification until the specified time.
The Mutex class is used to synchronize the execution of threads.
Definition: Mutex.h:70
The Semaphore class is used to manage and protect access to a set of shared resources.
Definition: Semaphore.h:50
#define MBED_DEPRECATED_SINCE(D, M)
MBED_DEPRECATED("message string") Mark a function declaration as deprecated, if it used then a warnin...