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.
Dependents: TYBLE16_simple_data_logger TYBLE16_MP3_Air
ConditionVariable.h
00001 /* Mbed Microcontroller Library 00002 * Copyright (c) 2017-2019 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 "rtos/mbed_rtos_types.h" 00027 #include "rtos/Mutex.h" 00028 #include "rtos/Semaphore.h" 00029 00030 #include "platform/NonCopyable.h" 00031 00032 #if MBED_CONF_RTOS_PRESENT || defined(DOXYGEN_ONLY) 00033 00034 namespace rtos { 00035 /** \addtogroup rtos-public-api */ 00036 /** @{*/ 00037 00038 struct Waiter; 00039 /** 00040 * \defgroup rtos_ConditionVariable ConditionVariable class 00041 * @{ 00042 */ 00043 00044 /** The ConditionVariable class is a synchronization primitive that allows 00045 * threads to wait until a particular condition occurs. 00046 * 00047 * Use the condition variable in conjunction with a mutex to safely wait for 00048 * or notify waiters of condition changes to a resource accessible by multiple 00049 * threads. 00050 * 00051 * The thread that intends to wait on a ConditionVariable must: 00052 * - Acquire a lock on a mutex. 00053 * - Execute `wait`, `wait_for` or `wait_until`. While the thread is waiting, 00054 * the mutex is unlocked. 00055 * - When the condition variable has been notified, or in the case of `wait_for` 00056 * and `wait_until` the timeout expires, the thread is awakened. 00057 * 00058 * The thread that intends to notify a ConditionVariable must: 00059 * - Acquire a lock on the mutex used to construct the condition variable. 00060 * - Execute `notify_one` or `notify_all` on the condition variable. 00061 * 00062 * All threads waiting on the condition variable wake when 00063 * `ConditionVariable::notify_all` is called. 00064 * At least one thread waiting on the condition variable wakes 00065 * when `ConditionVariable::notify_one` is called. 00066 * 00067 * While a thread is waiting for notification of a 00068 * ConditionVariable, it releases the lock held on the mutex. 00069 * The ConditionVariable reacquires the mutex lock before exiting the wait 00070 * function. 00071 * 00072 * #### Unspecified behavior 00073 * - The thread that is unblocked on `ConditionVariable::notify_one` is 00074 * unspecified if there are multiple waiters. 00075 * - When `ConditionVariable::notify_one` or `ConditionVariable::notify_all` is 00076 * called and there are one or more waiters, and one or more threads 00077 * attempting to acquire the condition variable's mutex, the order in which the mutex is 00078 * acquired is unspecified. 00079 * - Spurious notifications (not triggered by the application) can occur. 00080 * 00081 * #### Undefined behavior 00082 * - Calling wait if the mutex is not locked by the current thread is undefined 00083 * behavior. 00084 * - The order in which waiting threads acquire the condition variable's 00085 * mutex after `ConditionVariable::notify_all` is called is undefined. 00086 * - The behavior of `ConditionVariable::wait` and `ConditionVariable::wait_for` 00087 * is undefined if the condition variable's mutex is locked more than once by 00088 * the calling thread. 00089 * 00090 * @note Synchronization level: Thread safe 00091 * 00092 * Example: 00093 * 00094 * @code 00095 * #include "mbed.h" 00096 * 00097 * Mutex mutex; 00098 * ConditionVariable cv(mutex); 00099 * 00100 * // These variables are protected by locking the mutex. 00101 * uint32_t work_count = 0; 00102 * bool done = false; 00103 * 00104 * void worker_thread() 00105 * { 00106 * // Acquire lock on mutex before accessing protected variables and waiting. 00107 * mutex.lock(); 00108 * 00109 * while (done == false) { 00110 * printf("Worker thread: Count: %lu\r\n", work_count); 00111 * 00112 * // Wait for main thread to notify the condition variable. 00113 * printf("Worker thread: Waiting\r\n"); 00114 * cv.wait(); 00115 * } 00116 * 00117 * printf("Worker: Exiting\r\n"); 00118 * 00119 * // The condition variable acquires the lock when exiting the `wait` function. 00120 * // Unlock mutex when exiting the thread. 00121 * mutex.unlock(); 00122 * } 00123 * 00124 * int main() 00125 * { 00126 * Thread thread; 00127 * thread.start(worker_thread); 00128 * 00129 * for (int i = 0; i < 5; i++) { 00130 * // Acquire lock on mutex before modifying variables and notifying. 00131 * mutex.lock(); 00132 * 00133 * // Change count and notify waiters. 00134 * work_count++; 00135 * printf("Main thread: Set count to: %lu\r\n", work_count); 00136 * printf("Main thread: Notifying worker thread\r\n"); 00137 * cv.notify_all(); 00138 * 00139 * // Mutex must be unlocked before the worker thread can acquire it. 00140 * mutex.unlock(); 00141 * 00142 * wait(1.0); 00143 * } 00144 * 00145 * // Change done and notify waiters of this. 00146 * mutex.lock(); 00147 * done = true; 00148 * cv.notify_all(); 00149 * mutex.unlock(); 00150 * 00151 * thread.join(); 00152 * 00153 * printf("Main: Exiting\r\n"); 00154 * } 00155 * @endcode 00156 */ 00157 00158 class ConditionVariable : private mbed::NonCopyable<ConditionVariable> { 00159 public: 00160 /** Create and initialize a ConditionVariable object. 00161 * 00162 * @note You cannot call this function from ISR context. 00163 */ 00164 ConditionVariable(Mutex &mutex); 00165 00166 /** Wait for a notification. 00167 * 00168 * Wait causes the current thread to block until the condition variable 00169 * receives a notification from another thread. 00170 * 00171 * @note - The thread calling this function must be the owner of the 00172 * ConditionVariable's mutex, and it must be locked exactly once. 00173 * 00174 * @note - Spurious notifications can occur, so the caller of this API 00175 * should check to make sure the condition the caller is waiting on has 00176 * been met. 00177 * 00178 * @note - The current thread releases the lock while inside the wait 00179 * function and reacquires it upon exiting the function. 00180 * 00181 * Example: 00182 * @code 00183 * mutex.lock(); 00184 * 00185 * while (!condition_met) { 00186 * cond.wait(); 00187 * } 00188 * 00189 * function_to_handle_condition(); 00190 * 00191 * mutex.unlock(); 00192 * @endcode 00193 * 00194 * @note You cannot call this function from ISR context. 00195 */ 00196 void wait(); 00197 00198 /** Wait for a notification until the specified time. 00199 * 00200 * Wait until causes the current thread to block until the condition 00201 * variable is notified, or a specific time given by millisec parameter is 00202 * reached. 00203 * 00204 * @param millisec Absolute end time referenced to `Kernel::get_ms_count()` 00205 * @return `true` if a timeout occurred, `false` otherwise. 00206 * 00207 * @note - The thread calling this function must be the owner of the 00208 * ConditionVariable's mutex, and it must be locked exactly once. 00209 * 00210 * @note - Spurious notifications can occur, so the caller of this API 00211 * should check to make sure the condition the caller is waiting on has 00212 * been met. 00213 * 00214 * @note - The current thread releases the lock while inside the wait 00215 * function and reacquires it upon exiting the function. 00216 * 00217 * Example: 00218 * @code 00219 * mutex.lock(); 00220 * uint64_t end_time = Kernel::get_ms_count() + COND_WAIT_TIMEOUT; 00221 * 00222 * while (!condition_met) { 00223 * if (cond.wait_until(end_time)) { 00224 * break; 00225 * } 00226 * } 00227 * 00228 * if (condition_met) { 00229 * function_to_handle_condition(); 00230 * } 00231 * 00232 * mutex.unlock(); 00233 * @endcode 00234 * 00235 * @note You cannot call this function from ISR context. 00236 */ 00237 bool wait_until(uint64_t millisec); 00238 00239 /** Wait for a notification or timeout. 00240 * 00241 * `Wait for` causes the current thread to block until the condition 00242 * variable receives a notification from another thread, or the timeout 00243 * specified by the millisec parameter is reached. 00244 * 00245 * @param millisec Timeout value or osWaitForever in case of no timeout. 00246 * @return `true` if a timeout occurred, `false` otherwise. 00247 * 00248 * @note - The thread calling this function must be the owner of the 00249 * ConditionVariable's mutex, and it must be locked exactly once. 00250 * 00251 * @note - Spurious notifications can occur, so the caller of this API 00252 * should check to make sure the condition the caller is waiting on has 00253 * been met. 00254 * 00255 * @note - The current thread releases the lock while inside the wait 00256 * function and reacquire it upon exiting the function. 00257 * 00258 * Example: 00259 * @code 00260 * mutex.lock(); 00261 * 00262 * while (!condition_met) { 00263 * cond.wait_for(MAX_SLEEP_TIME); 00264 * if (!condition_met) { 00265 * do_other_work_while_condition_false(); 00266 * } 00267 * } 00268 * 00269 * if (condition_met) { 00270 * function_to_handle_condition(); 00271 * } 00272 * 00273 * mutex.unlock(); 00274 * @endcode 00275 * 00276 * @note You cannot call this function from ISR context. 00277 */ 00278 bool wait_for(uint32_t millisec); 00279 00280 /** Notify one waiter on this condition variable that a condition changed. 00281 * 00282 * This function unblocks one of the threads waiting for the condition 00283 * variable. 00284 * 00285 * @note - The thread calling this function must be the owner of the 00286 * ConditionVariable's mutex. 00287 * 00288 * @note - The thread that is unblocked on ConditionVariable::notify_one is 00289 * undefined if there are multiple waiters. 00290 * 00291 * @note You cannot call this function from ISR context. 00292 */ 00293 void notify_one(); 00294 00295 /** Notify all waiters on this condition variable that a condition changed. 00296 * 00297 * This function unblocks all of the threads waiting for the condition 00298 * variable. 00299 * 00300 * @note - The thread calling this function must be the owner of the 00301 * ConditionVariable's mutex. 00302 * 00303 * @note - If there are one or more waiters and one or more threads 00304 * attempting to acquire the condition variable's mutex the order in which 00305 * the mutex is acquired is undefined. 00306 * 00307 * @note You cannot call this function from ISR context. 00308 */ 00309 void notify_all(); 00310 00311 /** ConditionVariable destructor. 00312 * 00313 * @note You cannot call this function from ISR context. 00314 */ 00315 ~ConditionVariable(); 00316 00317 #if !defined(DOXYGEN_ONLY) 00318 protected: 00319 struct Waiter { 00320 Waiter(); 00321 Semaphore sem; 00322 Waiter *prev; 00323 Waiter *next; 00324 bool in_list; 00325 }; 00326 00327 static void _add_wait_list(Waiter **wait_list, Waiter *waiter); 00328 static void _remove_wait_list(Waiter **wait_list, Waiter *waiter); 00329 Mutex &_mutex; 00330 Waiter *_wait_list; 00331 #endif // !defined(DOXYGEN_ONLY) 00332 }; 00333 00334 /** @}*/ 00335 /** @}*/ 00336 } // namespace rtos 00337 #endif 00338 00339 #endif
Generated on Tue Jul 12 2022 13:54:13 by
1.7.2