Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
Dependencies: nRF51_Vdd TextLCD BME280
ConditionVariable.h
00001 /* Mbed Microcontroller Library 00002 * Copyright (c) 2017-2018 ARM Limited 00003 * 00004 * Permission is hereby granted, free of charge, to any person obtaining a copy 00005 * of this software and associated documentation files (the "Software"), to deal 00006 * in the Software without restriction, including without limitation the rights 00007 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 00008 * copies of the Software, and to permit persons to whom the Software is 00009 * furnished to do so, subject to the following conditions: 00010 * 00011 * The above copyright notice and this permission notice shall be included in 00012 * all copies or substantial portions of the Software. 00013 * 00014 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 00015 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 00016 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 00017 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 00018 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 00019 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 00020 * SOFTWARE. 00021 */ 00022 #ifndef CONDITIONVARIABLE_H 00023 #define CONDITIONVARIABLE_H 00024 00025 #include <stdint.h> 00026 #include "cmsis_os.h" 00027 #include "rtos/Mutex.h" 00028 #include "rtos/Semaphore.h" 00029 00030 #include "platform/NonCopyable.h" 00031 00032 namespace rtos { 00033 /** \addtogroup rtos */ 00034 /** @{*/ 00035 00036 struct Waiter; 00037 00038 /** The ConditionVariable class is a synchronization primitive that allows 00039 * threads to wait until a particular condition occurs. 00040 * 00041 * Use the condition variable in conjunction with a mutex to safely wait for 00042 * or notify waiters of condition changes to a resource accessible by multiple 00043 * threads. 00044 * 00045 * The thread that intends to wait on a ConditionVariable must: 00046 * - Acquire a lock on a mutex. 00047 * - Execute `wait`, `wait_for` or `wait_until`. While the thread is waiting, 00048 * the mutex is unlocked. 00049 * - When the condition variable has been notified, or in the case of `wait_for` 00050 * and `wait_until` the timeout expires, the thread is awakened. 00051 * 00052 * The thread that intends to notify a ConditionVariable must: 00053 * - Acquire a lock on the mutex used to construct the condition variable. 00054 * - Execute `notify_one` or `notify_all` on the condition variable. 00055 * 00056 * All threads waiting on the condition variable wake when 00057 * `ConditionVariable::notify_all` is called. 00058 * At least one thread waiting on the condition variable wakes 00059 * when `ConditionVariable::notify_one` is called. 00060 * 00061 * While a thread is waiting for notification of a 00062 * ConditionVariable, it releases the lock held on the mutex. 00063 * The ConditionVariable reacquires the mutex lock before exiting the wait 00064 * function. 00065 * 00066 * #### Unspecified behavior 00067 * - The thread that is unblocked on `ConditionVariable::notify_one` is 00068 * unspecified if there are multiple waiters. 00069 * - When `ConditionVariable::notify_one` or `ConditionVariable::notify_all` is 00070 * called and there are one or more waiters, and one or more threads 00071 * attempting to acquire the condition variable's mutex, the order in which the mutex is 00072 * acquired is unspecified. 00073 * - Spurious notifications (not triggered by the application) can occur. 00074 * 00075 * #### Undefined behavior 00076 * - Calling wait if the mutex is not locked by the current thread is undefined 00077 * behavior. 00078 * - The order in which waiting threads acquire the condition variable's 00079 * mutex after `ConditionVariable::notify_all` is called is undefined. 00080 * - The behavior of `ConditionVariable::wait` and `ConditionVariable::wait_for` 00081 * is undefined if the condition variable's mutex is locked more than once by 00082 * the calling thread. 00083 * 00084 * @note Synchronization level: Thread safe 00085 * 00086 * Example: 00087 * 00088 * @code 00089 * #include "mbed.h" 00090 * 00091 * Mutex mutex; 00092 * ConditionVariable cv(mutex); 00093 * 00094 * // These variables are protected by locking the mutex. 00095 * uint32_t work_count = 0; 00096 * bool done = false; 00097 * 00098 * void worker_thread() 00099 * { 00100 * // Acquire lock on mutex before accessing protected variables and waiting. 00101 * mutex.lock(); 00102 * 00103 * while (done == false) { 00104 * printf("Worker thread: Count: %lu\r\n", work_count); 00105 * 00106 * // Wait for main thread to notify the condition variable. 00107 * printf("Worker thread: Waiting\r\n"); 00108 * cv.wait(); 00109 * } 00110 * 00111 * printf("Worker: Exiting\r\n"); 00112 * 00113 * // The condition variable acquires the lock when exiting the `wait` function. 00114 * // Unlock mutex when exiting the thread. 00115 * mutex.unlock(); 00116 * } 00117 * 00118 * int main() 00119 * { 00120 * Thread thread; 00121 * thread.start(worker_thread); 00122 * 00123 * for (int i = 0; i < 5; i++) { 00124 * // Acquire lock on mutex before modifying variables and notifying. 00125 * mutex.lock(); 00126 * 00127 * // Change count and notify waiters. 00128 * work_count++; 00129 * printf("Main thread: Set count to: %lu\r\n", work_count); 00130 * printf("Main thread: Notifying worker thread\r\n"); 00131 * cv.notify_all(); 00132 * 00133 * // Mutex must be unlocked before the worker thread can acquire it. 00134 * mutex.unlock(); 00135 * 00136 * wait(1.0); 00137 * } 00138 * 00139 * // Change done and notify waiters of this. 00140 * mutex.lock(); 00141 * done = true; 00142 * cv.notify_all(); 00143 * mutex.unlock(); 00144 * 00145 * thread.join(); 00146 * 00147 * printf("Main: Exiting\r\n"); 00148 * } 00149 * @endcode 00150 */ 00151 00152 class ConditionVariable : private mbed::NonCopyable<ConditionVariable> { 00153 public: 00154 /** Create and initialize a ConditionVariable object. 00155 * 00156 * @note You cannot call this function from ISR context. 00157 */ 00158 ConditionVariable(Mutex &mutex); 00159 00160 /** Wait for a notification. 00161 * 00162 * Wait causes the current thread to block until the condition variable 00163 * receives a notification from another thread. 00164 * 00165 * @note - The thread calling this function must be the owner of the 00166 * ConditionVariable's mutex, and it must be locked exactly once. 00167 * 00168 * @note - Spurious notifications can occur, so the caller of this API 00169 * should check to make sure the condition the caller is waiting on has 00170 * been met. 00171 * 00172 * @note - The current thread releases the lock while inside the wait 00173 * function and reacquires it upon exiting the function. 00174 * 00175 * Example: 00176 * @code 00177 * mutex.lock(); 00178 * 00179 * while (!condition_met) { 00180 * cond.wait(); 00181 * } 00182 * 00183 * function_to_handle_condition(); 00184 * 00185 * mutex.unlock(); 00186 * @endcode 00187 * 00188 * @note You cannot call this function from ISR context. 00189 */ 00190 void wait(); 00191 00192 /** Wait for a notification until the specified time. 00193 * 00194 * Wait until causes the current thread to block until the condition 00195 * variable is notified, or a specific time given by millisec parameter is 00196 * reached. 00197 * 00198 * @param millisec Absolute end time referenced to `Kernel::get_ms_count()` 00199 * @return `true` if a timeout occurred, `false` otherwise. 00200 * 00201 * @note - The thread calling this function must be the owner of the 00202 * ConditionVariable's mutex, and it must be locked exactly once. 00203 * 00204 * @note - Spurious notifications can occur, so the caller of this API 00205 * should check to make sure the condition the caller is waiting on has 00206 * been met. 00207 * 00208 * @note - The current thread releases the lock while inside the wait 00209 * function and reacquires it upon exiting the function. 00210 * 00211 * Example: 00212 * @code 00213 * mutex.lock(); 00214 * uint64_t end_time = Kernel::get_ms_count() + COND_WAIT_TIMEOUT; 00215 * 00216 * while (!condition_met) { 00217 * if (cond.wait_until(end_time)) { 00218 * break; 00219 * } 00220 * } 00221 * 00222 * if (condition_met) { 00223 * function_to_handle_condition(); 00224 * } 00225 * 00226 * mutex.unlock(); 00227 * @endcode 00228 * 00229 * @note You cannot call this function from ISR context. 00230 */ 00231 bool wait_until(uint64_t millisec); 00232 00233 /** Wait for a notification or timeout. 00234 * 00235 * `Wait for` causes the current thread to block until the condition 00236 * variable receives a notification from another thread, or the timeout 00237 * specified by the millisec parameter is reached. 00238 * 00239 * @param millisec Timeout value or osWaitForever in case of no timeout. 00240 * @return `true` if a timeout occurred, `false` otherwise. 00241 * 00242 * @note - The thread calling this function must be the owner of the 00243 * ConditionVariable's mutex, and it must be locked exactly once. 00244 * 00245 * @note - Spurious notifications can occur, so the caller of this API 00246 * should check to make sure the condition the caller is waiting on has 00247 * been met. 00248 * 00249 * @note - The current thread releases the lock while inside the wait 00250 * function and reacquire it upon exiting the function. 00251 * 00252 * Example: 00253 * @code 00254 * mutex.lock(); 00255 * 00256 * while (!condition_met) { 00257 * cond.wait_for(MAX_SLEEP_TIME); 00258 * if (!condition_met) { 00259 * do_other_work_while_condition_false(); 00260 * } 00261 * } 00262 * 00263 * if (condition_met) { 00264 * function_to_handle_condition(); 00265 * } 00266 * 00267 * mutex.unlock(); 00268 * @endcode 00269 * 00270 * @note You cannot call this function from ISR context. 00271 */ 00272 bool wait_for(uint32_t millisec); 00273 00274 /** Notify one waiter on this condition variable that a condition changed. 00275 * 00276 * This function unblocks one of the threads waiting for the condition 00277 * variable. 00278 * 00279 * @note - The thread calling this function must be the owner of the 00280 * ConditionVariable's mutex. 00281 * 00282 * @note - The thread that is unblocked on ConditionVariable::notify_one is 00283 * undefined if there are multiple waiters. 00284 * 00285 * @note You cannot call this function from ISR context. 00286 */ 00287 void notify_one(); 00288 00289 /** Notify all waiters on this condition variable that a condition changed. 00290 * 00291 * This function unblocks all of the threads waiting for the condition 00292 * variable. 00293 * 00294 * @note - The thread calling this function must be the owner of the 00295 * ConditionVariable's mutex. 00296 * 00297 * @note - If there are one or more waiters and one or more threads 00298 * attempting to acquire the condition variable's mutex the order in which 00299 * the mutex is acquired is undefined. 00300 * 00301 * @note You cannot call this function from ISR context. 00302 */ 00303 void notify_all(); 00304 00305 /** ConditionVariable destructor. 00306 * 00307 * @note You cannot call this function from ISR context. 00308 */ 00309 ~ConditionVariable(); 00310 00311 #if !defined(DOXYGEN_ONLY) 00312 protected: 00313 struct Waiter { 00314 Waiter(); 00315 Semaphore sem; 00316 Waiter *prev; 00317 Waiter *next; 00318 bool in_list; 00319 }; 00320 00321 static void _add_wait_list(Waiter **wait_list, Waiter *waiter); 00322 static void _remove_wait_list(Waiter **wait_list, Waiter *waiter); 00323 Mutex &_mutex; 00324 Waiter *_wait_list; 00325 #endif // !defined(DOXYGEN_ONLY) 00326 }; 00327 00328 } 00329 #endif 00330 00331 /** @}*/
Generated on Tue Jul 12 2022 15:15:42 by
