Marco Zecchini
/
Example_RTOS
Rtos API example
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 ConditionVariable(Mutex &mutex); 00123 00124 /** Wait for a notification 00125 * 00126 * Wait until a notification occurs. 00127 * 00128 * @note - The thread calling this function must be the owner of the 00129 * ConditionVariable's mutex and it must be locked exactly once 00130 * @note - Spurious notifications can occur so the caller of this API 00131 * should check to make sure the condition they are waiting on has 00132 * been met 00133 * 00134 * Example: 00135 * @code 00136 * mutex.lock(); 00137 * while (!condition_met) { 00138 * cond.wait(); 00139 * } 00140 * 00141 * function_to_handle_condition(); 00142 * 00143 * mutex.unlock(); 00144 * @endcode 00145 */ 00146 void wait(); 00147 00148 /** Wait for a notification or timeout 00149 * 00150 * @param millisec timeout value or osWaitForever in case of no time-out. 00151 * @return true if a timeout occurred, false otherwise. 00152 * 00153 * @note - The thread calling this function must be the owner of the 00154 * ConditionVariable's mutex and it must be locked exactly once 00155 * @note - Spurious notifications can occur so the caller of this API 00156 * should check to make sure the condition they are waiting on has 00157 * been met 00158 * 00159 * Example: 00160 * @code 00161 * mutex.lock(); 00162 * Timer timer; 00163 * timer.start(); 00164 * 00165 * bool timed_out = false; 00166 * uint32_t time_left = TIMEOUT; 00167 * while (!condition_met && !timed_out) { 00168 * timed_out = cond.wait_for(time_left); 00169 * uint32_t elapsed = timer.read_ms(); 00170 * time_left = elapsed > TIMEOUT ? 0 : TIMEOUT - elapsed; 00171 * } 00172 * 00173 * if (condition_met) { 00174 * function_to_handle_condition(); 00175 * } 00176 * 00177 * mutex.unlock(); 00178 * @endcode 00179 */ 00180 bool wait_for(uint32_t millisec); 00181 00182 /** Notify one waiter on this condition variable that a condition changed. 00183 * 00184 * @note - The thread calling this function must be the owner of the ConditionVariable's mutex 00185 */ 00186 void notify_one(); 00187 00188 /** Notify all waiters on this condition variable that a condition changed. 00189 * 00190 * @note - The thread calling this function must be the owner of the ConditionVariable's mutex 00191 */ 00192 void notify_all(); 00193 00194 ~ConditionVariable(); 00195 00196 protected: 00197 struct Waiter { 00198 Waiter(); 00199 Semaphore sem; 00200 Waiter *prev; 00201 Waiter *next; 00202 bool in_list; 00203 }; 00204 00205 static void _add_wait_list(Waiter **wait_list, Waiter *waiter); 00206 static void _remove_wait_list(Waiter **wait_list, Waiter *waiter); 00207 Mutex &_mutex; 00208 Waiter *_wait_list; 00209 }; 00210 00211 } 00212 #endif 00213 00214 /** @}*/
Generated on Sun Jul 17 2022 08:25:21 by 1.7.2