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