Kenji Arai / TYBLE16_mbedlized_os5_several_examples_1st

Dependencies:   nRF51_Vdd TextLCD BME280

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers ConditionVariable.h Source File

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 /** @}*/