Kenji Arai / mbed-os_TYBLE16

Dependents:   TYBLE16_simple_data_logger TYBLE16_MP3_Air

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-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