init
Embed:
(wiki syntax)
Show/hide line numbers
ConditionVariable.h
00001 /* mbed Microcontroller Library 00002 * Copyright (c) 2017-2017 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 /** This class provides a safe way to wait for or send notifications of condition changes 00039 * 00040 * This class is used in conjunction with a mutex to safely wait for or 00041 * notify waiters of condition changes to a resource accessible by multiple 00042 * threads. 00043 * 00044 * # Defined behavior 00045 * - All threads waiting on the condition variable wake when 00046 * ConditionVariable::notify_all is called. 00047 * - If one or more threads are waiting on the condition variable at least 00048 * one of them wakes when ConditionVariable::notify is called. 00049 * 00050 * # Undefined behavior 00051 * - The thread which is unblocked on ConditionVariable::notify_one is 00052 * undefined if there are multiple waiters. 00053 * - The order which in which waiting threads acquire the condition variable's 00054 * mutex after ConditionVariable::notify_all is called is undefined. 00055 * - When ConditionVariable::notify_one or ConditionVariable::notify_all is 00056 * called and there are one or more waiters and one or more threads attempting 00057 * to acquire the condition variable's mutex the order in which the mutex is 00058 * acquired is undefined. 00059 * - The behavior of ConditionVariable::wait and ConditionVariable::wait_for 00060 * is undefined if the condition variable's mutex is locked more than once by 00061 * the calling thread. 00062 * - Spurious notifications (not triggered by the application) can occur 00063 * and it is not defined when these occur. 00064 * 00065 * @note Synchronization level: Thread safe 00066 * 00067 * Example: 00068 * @code 00069 * #include "mbed.h" 00070 * 00071 * Mutex mutex; 00072 * ConditionVariable cond(mutex); 00073 * 00074 * // These variables are protected by locking mutex 00075 * uint32_t count = 0; 00076 * bool done = false; 00077 * 00078 * void worker_thread() 00079 * { 00080 * mutex.lock(); 00081 * do { 00082 * printf("Worker: Count %lu\r\n", count); 00083 * 00084 * // Wait for a condition to change 00085 * cond.wait(); 00086 * 00087 * } while (!done); 00088 * printf("Worker: Exiting\r\n"); 00089 * mutex.unlock(); 00090 * } 00091 * 00092 * int main() { 00093 * Thread thread; 00094 * thread.start(worker_thread); 00095 * 00096 * for (int i = 0; i < 5; i++) { 00097 * 00098 * mutex.lock(); 00099 * // Change count and notify waiters of this 00100 * count++; 00101 * printf("Main: Set count to %lu\r\n", count); 00102 * cond.notify_all(); 00103 * mutex.unlock(); 00104 * 00105 * wait(1.0); 00106 * } 00107 * 00108 * mutex.lock(); 00109 * // Change done and notify waiters of this 00110 * done = true; 00111 * printf("Main: Set done\r\n"); 00112 * cond.notify_all(); 00113 * mutex.unlock(); 00114 * 00115 * thread.join(); 00116 * } 00117 * @endcode 00118 */ 00119 class ConditionVariable : private mbed::NonCopyable<ConditionVariable> { 00120 public: 00121 /** Create and Initialize a ConditionVariable object 00122 * 00123 * @note You cannot call this function from ISR context. 00124 */ 00125 ConditionVariable(Mutex &mutex); 00126 00127 /** Wait for a notification 00128 * 00129 * Wait until a notification occurs. 00130 * 00131 * @note - The thread calling this function must be the owner of the 00132 * ConditionVariable's mutex and it must be locked exactly once 00133 * @note - Spurious notifications can occur so the caller of this API 00134 * should check to make sure the condition they are waiting on has 00135 * been met 00136 * 00137 * Example: 00138 * @code 00139 * mutex.lock(); 00140 * while (!condition_met) { 00141 * cond.wait(); 00142 * } 00143 * 00144 * function_to_handle_condition(); 00145 * 00146 * mutex.unlock(); 00147 * @endcode 00148 * 00149 * @note You cannot call this function from ISR context. 00150 */ 00151 void wait(); 00152 00153 /** Wait for a notification until specified time 00154 * 00155 * @param millisec absolute end time referenced to Kernel::get_ms_count() 00156 * @return true if a timeout occurred, false otherwise. 00157 * 00158 * @note - The thread calling this function must be the owner of the 00159 * ConditionVariable's mutex and it must be locked exactly once 00160 * @note - Spurious notifications can occur so the caller of this API 00161 * should check to make sure the condition they are waiting on has 00162 * been met 00163 * 00164 * Example: 00165 * @code 00166 * mutex.lock(); 00167 * uint64_t end_time = Kernel::get_ms_count() + COND_WAIT_TIMEOUT; 00168 * 00169 * while (!condition_met) { 00170 * if (cond.wait_until(end_time)) { 00171 * break; 00172 * } 00173 * } 00174 * 00175 * if (condition_met) { 00176 * function_to_handle_condition(); 00177 * } 00178 * 00179 * mutex.unlock(); 00180 * @endcode 00181 * 00182 * @note You cannot call this function from ISR context. 00183 */ 00184 bool wait_until(uint64_t millisec); 00185 00186 /** Wait for a notification or timeout 00187 * 00188 * @param millisec timeout value or osWaitForever in case of no time-out. 00189 * @return true if a timeout occurred, false otherwise. 00190 * 00191 * @note - The thread calling this function must be the owner of the 00192 * ConditionVariable's mutex and it must be locked exactly once 00193 * @note - Spurious notifications can occur so the caller of this API 00194 * should check to make sure the condition they are waiting on has 00195 * been met 00196 * 00197 * Example: 00198 * @code 00199 * mutex.lock(); 00200 * 00201 * while (!condition_met) { 00202 * cond.wait_for(MAX_SLEEP_TIME); 00203 * if (!condition_met) { 00204 * do_other_work_while_condition_false(); 00205 * } 00206 * } 00207 * 00208 * if (condition_met) { 00209 * function_to_handle_condition(); 00210 * } 00211 * 00212 * mutex.unlock(); 00213 * @endcode 00214 * 00215 * @note You cannot call this function from ISR context. 00216 */ 00217 bool wait_for(uint32_t millisec); 00218 00219 /** Notify one waiter on this condition variable that a condition changed. 00220 * 00221 * @note - The thread calling this function must be the owner of the ConditionVariable's mutex 00222 * 00223 * @note You cannot call this function from ISR context. 00224 */ 00225 void notify_one(); 00226 00227 /** Notify all waiters on this condition variable that a condition changed. 00228 * 00229 * @note - The thread calling this function must be the owner of the ConditionVariable's mutex 00230 * 00231 * @note You cannot call this function from ISR context. 00232 */ 00233 void notify_all(); 00234 00235 /** ConditionVariable destructor 00236 * 00237 * @note You cannot call this function from ISR context. 00238 */ 00239 ~ConditionVariable(); 00240 00241 protected: 00242 struct Waiter { 00243 Waiter(); 00244 Semaphore sem; 00245 Waiter *prev; 00246 Waiter *next; 00247 bool in_list; 00248 }; 00249 00250 static void _add_wait_list(Waiter **wait_list, Waiter *waiter); 00251 static void _remove_wait_list(Waiter **wait_list, Waiter *waiter); 00252 Mutex &_mutex; 00253 Waiter *_wait_list; 00254 }; 00255 00256 } 00257 #endif 00258 00259 /** @}*/
Generated on Tue Jul 12 2022 13:24:36 by
1.7.2