Rtos API example

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