µOS++ IIIe Reference  v6.3.15
“Perfekt ist nicht gut genug”
The third edition of µOS++, a POSIX inspired open source system, written in C++.
os::rtos::condition_variable Class Reference

POSIX compliant condition variable. More...

#include <cmsis-plus/rtos/os.h>

Inherits os::rtos::internal::object_named_system.

Classes

class  attributes
 Condition variable attributes. More...
 

Public Member Functions

Constructors & Destructor
 condition_variable (const attributes &attr=initializer)
 Construct a condition variable object instance. More...
 
 condition_variable (const char *name, const attributes &attr=initializer)
 Construct a named condition variable object instance. More...
 
 ~condition_variable ()
 Destruct the condition variable object instance. More...
 
Operators
bool operator== (const condition_variable &rhs) const
 Compare condition variables. More...
 
Public Member Functions
result_t signal (void)
 Notify one thread waiting for a condition variable. More...
 
result_t broadcast (void)
 Notify all threads waiting for a condition variable. More...
 
result_t wait (mutex &mutex)
 Wait for a condition variable to be notified. More...
 
result_t timed_wait (mutex &mutex, clock::duration_t timeout)
 Timed wait for a condition variable to be notified. More...
 
Public Member Functions
const char * name (void) const
 Get object name. More...
 

Static Public Member Functions

Operators
static void * operator new (std::size_t bytes)
 Allocate space for a new object instance using the RTOS system allocator. More...
 
static void * operator new (std::size_t bytes, void *ptr)
 Emplace a new object instance. More...
 
static void * operator new[] (std::size_t bytes)
 Allocate space for an array of new object instances using the RTOS system allocator. More...
 
static void * operator new[] (std::size_t bytes, void *ptr)
 Emplace an array of new object instances. More...
 
static void operator delete (void *ptr, std::size_t bytes)
 Deallocate the dynamically allocated object instance. using the RTOS system allocator. More...
 
static void operator delete[] (void *ptr, std::size_t bytes)
 Deallocate the dynamically allocated array of object. instances using the RTOS system allocator. More...
 

Static Public Attributes

static const attributes initializer
 Default condition variable initialiser. More...
 

Detailed Description

POSIX compliant condition variable.

A condition variable is a synchronisation object which allows a thread to suspend execution, repeatedly, until some associated predicate becomes true. A thread whose execution is suspended on a condition variable is said to be blocked on the condition variable.

Scheduling Behaviour of Condition Variables

Synchronisation primitives that attempt to interfere with scheduling policy by specifying an ordering rule are considered undesirable. Threads waiting on mutexes and condition variables are selected to proceed in an order dependent upon the scheduling policy rather than in some fixed order (for example, FIFO or priority). Thus, the scheduling policy determines which thread(s) are awakened and allowed to proceed.

Cancellation and Condition Wait

A condition wait, whether timed or not, is a cancellation point. That is, the functions wait() or timed_wait() are points where a pending (or concurrent) cancellation request is noticed. The reason for this is that an indefinite wait is possible at these points-whatever event is being waited for, even if the program is totally correct, might never occur; for example, some input data being awaited might never be sent. By making condition wait a cancellation point, the thread can be cancelled and perform its cancellation cleanup handler even though it may be stuck in some indefinite wait.

A side-effect of acting on a cancellation request while a thread is blocked on a condition variable is to re-acquire the mutex before calling any of the cancellation cleanup handlers. This is done in order to ensure that the cancellation cleanup handler is executed in the same state as the critical code that lies both before and after the call to the condition wait function. This rule is also required when interfacing to POSIX threads from languages, such as Ada or C++, which may choose to map cancellation onto a language exception; this rule ensures that each exception handler guarding a critical section can always safely depend upon the fact that the associated mutex has already been locked regardless of exactly where within the critical section the exception was raised. Without this rule, there would not be a uniform rule that exception handlers could follow regarding the lock, and so coding would become very cumbersome.

Therefore, since some statement has to be made regarding the state of the lock when a cancellation is delivered during a wait, a definition has been chosen that makes application coding most convenient and error free.

When acting on a cancellation request while a thread is blocked on a condition variable, the implementation is required to ensure that the thread does not consume any condition signals directed at that condition variable if there are any other threads waiting on that condition variable. This rule is specified in order to avoid deadlock conditions that could occur if these two independent requests (one acting on a thread and the other acting on the condition variable) were not processed independently.

Performance of Mutexes and Condition Variables

Mutexes are expected to be locked only for a few instructions. This practice is almost automatically enforced by the desire of programmers to avoid long serial regions of execution (which would reduce total effective parallelism).

When using mutexes and condition variables, one tries to ensure that the usual case is to lock the mutex, access shared data, and unlock the mutex. Waiting on a condition variable should be a relatively rare situation. For example, when implementing a read-write lock, code that acquires a read-lock typically needs only to increment the count of readers (under mutual-exclusion) and return. The calling thread would actually wait on the condition variable only when there is already an active writer. So the efficiency of a synchronisation operation is bounded by the cost of mutex lock/unlock and not by condition wait. Note that in the usual case there is no context switch.

This is not to say that the efficiency of condition waiting is unimportant. Since there needs to be at least one context switch per Ada rendezvous, the efficiency of waiting on a condition variable is important. The cost of waiting on a condition variable should be little more than the minimal cost for a context switch plus the time to unlock and lock the mutex.

Example
mutex mx;
void
consumer(void)
{
// Do something
mx.lock();
// ...
while(!condition())
{
// ...
cv.wait();
// ...
}
// ...
mx.unlock(mx);
// Do something else.
}
void
producer(void)
{
// Do something
mx.lock();
// ...
if (some_condition())
{
// ...
cv.signal();
// ...
}
// ...
mx.unlock(mx);
// Do something else.
}
POSIX compatibility
Inspired by pthread_cond_t from <pthread.h> (IEEE Std 1003.1, 2013 Edition).

Definition at line 51 of file os-condvar.h.

Constructor & Destructor Documentation

◆ condition_variable() [1/2]

os::rtos::condition_variable::condition_variable ( const attributes attr = initializer)

Construct a condition variable object instance.

Parameters
[in]attrReference to attributes.
Errors
The constructor shall fail if:
  • EAGAIN - The system lacked the necessary resources (other than memory) to create the condition variable.
  • ENOMEM - Insufficient memory exists to initialise the condition variable.
The constructor shall not fail with an error code of EINTR.

This constructor shall initialise a condition variable object with attributes referenced by attr. If the attributes specified by attr are modified later, the condition variable attributes shall not be affected.

Upon successful initialisation, the state of the condition variable object shall become initialised.

Only the condition variable object itself may be used for performing synchronisation. It is not allowed to make copies of condition variable objects.

In cases where default condition variable attributes are appropriate, the variable condition_variable::initializer can be used to initialise condition variables. The effect shall be equivalent to creating a condition variables object with the default constructor.

Warning
Cannot be invoked from Interrupt Service Routines.
POSIX compatibility
Inspired by pthread_cond_init() from <pthread.h> (IEEE Std 1003.1, 2013 Edition).

Definition at line 226 of file os-condvar.cpp.

◆ condition_variable() [2/2]

os::rtos::condition_variable::condition_variable ( const char *  name,
const attributes attr = initializer 
)

Construct a named condition variable object instance.

Parameters
[in]namePointer to name.
[in]attrReference to attributes.
Errors
The constructor shall fail if:
  • EAGAIN - The system lacked the necessary resources (other than memory) to create the condition variable.
  • ENOMEM - Insufficient memory exists to initialise the condition variable.
The constructor shall not fail with an error code of EINTR.

This constructor shall initialise a named condition variable object with attributes referenced by attr. If the attributes specified by attr are modified later, the condition variable attributes shall not be affected.

Upon successful initialisation, the state of the condition variable object shall become initialised.

Only the condition variable object itself may be used for performing synchronisation. It is not allowed to make copies of condition variable objects.

In cases where default condition variable attributes are appropriate, the variable condition_variable::initializer can be used to initialise condition variables. The effect shall be equivalent to creating a condition variables object with the default constructor.

Warning
Cannot be invoked from Interrupt Service Routines.
POSIX compatibility
Inspired by pthread_cond_init() from <pthread.h> (IEEE Std 1003.1, 2013 Edition).

Definition at line 260 of file os-condvar.cpp.

◆ ~condition_variable()

os::rtos::condition_variable::~condition_variable ( )

Destruct the condition variable object instance.

This destructor shall destroy the condition variable object; the object becomes, in effect, uninitialised. An implementation may cause the destructor to set the object to an invalid value.

It shall be safe to destroy an initialised condition variable object upon which no threads are currently blocked. Attempting to destroy a condition variable object upon which other threads are currently blocked results in undefined behaviour.

Warning
Cannot be invoked from Interrupt Service Routines.
POSIX compatibility
Inspired by pthread_cond_destroy() from <pthread.h> (IEEE Std 1003.1, 2013 Edition).

Definition at line 291 of file os-condvar.cpp.

Member Function Documentation

◆ broadcast()

result_t os::rtos::condition_variable::broadcast ( void  )

Notify all threads waiting for a condition variable.

Parameters
None.
Return values
result::okAll waiting threads signalled.
EPERMCannot be invoked from an Interrupt Service Routines.
Errors
The function shall not fail with an error code of EINTR.

Unblock all threads currently blocked on the specified condition variable.

If more than one thread are blocked on a condition variable, the scheduling policy shall determine the order in which threads are unblocked.

When each thread unblocked as a result of a broadcast() returns from its call to wait() or timed_wait(), the thread shall own the mutex with which it called wait() or timed_wait(). The thread(s) that are unblocked shall contend for the mutex according to the scheduling policy (if applicable), and as if each had called mutex::lock().

broadcast() may be called by a thread whether or not it currently owns the mutex that threads calling wait() or timed_wait() have associated with the condition variable during their waits; however, if predictable scheduling behaviour is required, then that mutex shall be locked by the thread calling broadcast().

The broadcast() function shall have no effect if there are no threads currently blocked on this condition variable.

Application usage
The broadcast() function is used whenever the shared-variable state has been changed in a way that more than one thread can proceed with its task. Consider a single producer/multiple consumer problem, where the producer can insert multiple items on a list that is accessed one item at a time by the consumers. By calling the broadcast() function, the producer would notify all consumers that might be waiting, and thereby the application would receive more throughput on a multi-processor. In addition, broadcast() makes it easier to implement a read-write lock. The broadcast() function is needed in order to wake up all waiting readers when a writer releases its lock. Finally, the two-phase commit algorithm can use this broadcast function to notify all clients of an impending transaction commit.
Warning
Cannot be invoked from Interrupt Service Routines.
POSIX compatibility
Inspired by pthread_cond_broadcast() from <pthread.h> (IEEE Std 1003.1, 2013 Edition).

Definition at line 406 of file os-condvar.cpp.

◆ name()

const char * os::rtos::internal::object_named::name ( void  ) const
inlineinherited

Get object name.

Parameters
None.
Returns
A null terminated string.

All objects return a non-null string; anonymous objects return "-".

Note
Can be invoked from Interrupt Service Routines.

Definition at line 760 of file os-decls.h.

◆ operator delete()

void os::rtos::internal::object_named_system::operator delete ( void *  ptr,
std::size_t  bytes 
)
inlinestaticinherited

Deallocate the dynamically allocated object instance. using the RTOS system allocator.

Parameters
ptrPointer to object.
bytesNumber of bytes to deallocate.
Returns
Nothing.

The deallocation function (3.7.4.2) called by a delete-expression to render the value of ptr invalid.

ptr shall be a null pointer or its value shall be a value returned by an earlier call to the (possibly replaced) operator new() which has not been invalidated by an intervening call to operator delete(void*).

If ptr is null, does nothing. Otherwise, reclaims the storage allocated by the earlier call to operator new.

The storage is deallocated using the RTOS system allocator.

Warning
Cannot be invoked from Interrupt Service Routines.

Definition at line 134 of file os-inlines.h.

◆ operator delete[]()

void os::rtos::internal::object_named_system::operator delete[] ( void *  ptr,
std::size_t  bytes 
)
inlinestaticinherited

Deallocate the dynamically allocated array of object. instances using the RTOS system allocator.

Parameters
ptrPointer to array of objects.
bytesNumber of bytes to deallocate.
Returns
Nothing.

The deallocation function (3.7.4.2) called by the array form of a delete-expression to render the value of ptr invalid.

If ptr is null, does nothing. Otherwise, reclaims the storage allocated by the earlier call to operator new.

The storage is deallocated using the RTOS system allocator.

Warning
Cannot be invoked from Interrupt Service Routines.

Definition at line 155 of file os-inlines.h.

◆ operator new() [1/2]

void * os::rtos::internal::object_named_system::operator new ( std::size_t  bytes)
inlinestaticinherited

Allocate space for a new object instance using the RTOS system allocator.

Parameters
bytesNumber of bytes to allocate.
Returns
Pointer to allocated object.

The allocation function (3.7.4.1) called by a new-expression (5.3.4) to allocate a storage of size bytes suitably aligned to represent any object of that size. Return a non-null pointer to suitably aligned storage (3.7.4).

The storage is allocated using the RTOS system allocator.

Warning
Cannot be invoked from Interrupt Service Routines.

Definition at line 56 of file os-inlines.h.

◆ operator new() [2/2]

void * os::rtos::internal::object_named_system::operator new ( std::size_t  bytes,
void *  ptr 
)
inlinestaticinherited

Emplace a new object instance.

Parameters
bytesNumber of bytes to emplace.
ptrPointer to location to emplace the object.
Returns
Pointer to emplaced object.

The allocation function (3.7.4.1) called by a placement new-expression to allocate a storage of size bytes suitably aligned to represent any object of that size. Return a non-null pointer to suitably aligned storage (3.7.4).

The storage is allocated using the RTOS system allocator.

Warning
Cannot be invoked from Interrupt Service Routines.

Definition at line 93 of file os-inlines.h.

◆ operator new[]() [1/2]

void * os::rtos::internal::object_named_system::operator new[] ( std::size_t  bytes)
inlinestaticinherited

Allocate space for an array of new object instances using the RTOS system allocator.

Parameters
bytesNumber of bytes to allocate.
Returns
Pointer to allocated array.

The allocation function (3.7.4.1) called by the array form of a new-expression (5.3.4) to allocate a storage of size bytes suitably aligned to represent any array object of that size or smaller.

The storage is allocated using the RTOS system allocator.

Warning
Cannot be invoked from Interrupt Service Routines.

Definition at line 74 of file os-inlines.h.

◆ operator new[]() [2/2]

void * os::rtos::internal::object_named_system::operator new[] ( std::size_t  bytes,
void *  ptr 
)
inlinestaticinherited

Emplace an array of new object instances.

Parameters
bytesNumber of bytes to emplace.
ptrPointer to location to emplace the object.
Returns
Pointer to emplaced array.

The allocation function (3.7.4.1) called by the array form of a placement new-expression to allocate a storage of size bytes suitably aligned to represent any array object of that size or smaller.

The storage is allocated using the RTOS system allocator.

Warning
Cannot be invoked from Interrupt Service Routines.

Definition at line 110 of file os-inlines.h.

◆ operator==()

bool os::rtos::condition_variable::operator== ( const condition_variable rhs) const
inline

Compare condition variables.

Return values
trueThe given condition variable is the same as this condition variable.
falseThe condition variables are different.

Identical condition variables should have the same memory address.

Definition at line 326 of file os-condvar.h.

◆ signal()

result_t os::rtos::condition_variable::signal ( void  )

Notify one thread waiting for a condition variable.

Parameters
None.
Return values
result::okThe thread was signalled.
EPERMCannot be invoked from an Interrupt Service Routines.
Errors
The function shall not fail with an error code of EINTR.

Unblock at least one of the threads that are blocked on the specified condition variable.

When each thread unblocked as a result of a signal() returns from its call to wait() or timed_wait(), the thread shall own the mutex with which it called wait() or timed_wait(). The thread(s) that are unblocked shall contend for the mutex according to the scheduling policy (if applicable), and as if each had called mutex::lock().

signal() may be called by a thread whether or not it currently owns the mutex that threads calling wait() or timed_wait() have associated with the condition variable during their waits; however, if predictable scheduling behaviour is required, then that mutex shall be locked by the thread calling signal().

The signal() function shall have no effect if there are no threads currently blocked on this condition variable.

Warning
Cannot be invoked from Interrupt Service Routines.
POSIX compatibility
Inspired by pthread_cond_signal() from <pthread.h> (IEEE Std 1003.1, 2013 Edition).

Definition at line 336 of file os-condvar.cpp.

◆ timed_wait()

result_t os::rtos::condition_variable::timed_wait ( mutex mutex,
clock::duration_t  timeout 
)

Timed wait for a condition variable to be notified.

Parameters
[in]mutexReference to the associated mutex.
[in]timeoutTimeout to wait.
Return values
result::okThe condition change was signalled.
EPERMCannot be invoked from an Interrupt Service Routines, or the mutex type is mutex::type::errorcheck or the mutex is a robust mutex, and the current thread does not own the mutex.
ENOTRECOVERABLEThe state protected by the mutex is not recoverable.
EOWNERDEADThe mutex is a robust mutex and the process containing the previous owning thread terminated while holding the mutex lock. The mutex lock shall be acquired by the calling thread and it is up to the new owner to make the state consistent.
ETIMEDOUTThe timeout has passed.
Errors
The function shall not fail with an error code of EINTR.

Block on a condition variable. The application shall ensure that this function is called with mutex locked by the calling thread; otherwise, an error (for mutex::type::errorcheck and robust mutexes) or undefined behaviour (for other mutexes) results.

These functions atomically release mutex and cause the calling thread to block on the condition variable cond; atomically here means "atomically with respect to access by another thread to the mutex and then the condition variable". That is, if another thread is able to acquire the mutex after the about-to-block thread has released it, then a subsequent call to broadcast() or signal() in that thread shall behave as if it were issued after the about-to-block thread has blocked.

Upon successful return, the mutex shall have been locked and shall be owned by the calling thread. If mutex is a robust mutex where an owner terminated while holding the lock and the state is recoverable, the mutex shall be acquired even though the function returns an error code.

When using condition variables there is always a Boolean predicate involving shared variables associated with each condition wait that is true if the thread should proceed. Spurious wakeups from the timed_wait() functions may occur. Since the return from timed_wait() does not imply anything about the value of this predicate, the predicate should be re-evaluated upon such return.

When a thread waits on a condition variable, having specified a particular mutex to either the timed_wait() operation, a dynamic binding is formed between that mutex and condition variable that remains in effect as long as at least one thread is blocked on the condition variable. During this time, the effect of an attempt by any thread to wait on that condition variable using a different mutex is undefined. Once all waiting threads have been unblocked (as by the broadcast() operation), the next wait operation on that condition variable shall form a new dynamic binding with the mutex specified by that wait operation. Even though the dynamic binding between condition variable and mutex may be removed or replaced between the time a thread is unblocked from a wait on the condition variable and the time that it returns to the caller or begins cancellation cleanup, the unblocked thread shall always re-acquire the mutex specified in the condition wait operation call from which it is returning.

A condition wait (whether timed or not) is a cancellation point. When the cancellability type of a thread is set to PTHREAD_CANCEL_DEFERRED, a side-effect of acting upon a cancellation request while in a condition wait is that the mutex is (in effect) re-acquired before calling the first cancellation cleanup handler. The effect is as if the thread were unblocked, allowed to execute up to the point of returning from the call to timed_wait(), but at that point notices the cancellation request and instead of returning to the caller of timed_wait() or wait(), starts the thread cancellation activities, which includes calling cancellation cleanup handlers.

A thread that has been unblocked because it has been cancelled while blocked in a call to timed_wait() shall not consume any condition signal that may be directed concurrently at the condition variable if there are other threads blocked on the condition variable.

The timed_wait() function shall be equivalent to wait(), except that an error is returned if the timeout specified by timeout passes (that is, system time equals or exceeds now() + timeout) before the condition cond is signalled or broadcasted. When such timeouts occur, timed_wait() shall nonetheless release and re-acquire the mutex referenced by mutex, and may consume a condition signal directed concurrently at the condition variable.

The condition variable shall have a clock attribute which specifies the clock that shall be used to measure the time specified by the ticks argument. The timed_wait() function is also a cancellation point. The resolution of the timeout shall be the resolution of the clock on which it is based (by default the SysTick clock for CMSIS).

Warning
Cannot be invoked from Interrupt Service Routines.
POSIX compatibility
Inspired by pthread_cond_timedwait() from <pthread.h> (IEEE Std 1003.1, 2013 Edition).

Definition at line 651 of file os-condvar.cpp.

◆ wait()

result_t os::rtos::condition_variable::wait ( mutex mutex)

Wait for a condition variable to be notified.

Parameters
[in]mutexReference to the associated mutex.
Return values
result::okThe condition change was signalled.
EPERMCannot be invoked from an Interrupt Service Routines, or the mutex type is mutex::type::errorcheck or the mutex is a robust mutex, and the current thread does not own the mutex.
ENOTRECOVERABLEThe state protected by the mutex is not recoverable.
EOWNERDEADThe mutex is a robust mutex and the process containing the previous owning thread terminated while holding the mutex lock. The mutex lock shall be acquired by the calling thread and it is up to the new owner to make the state consistent.
Errors
The function shall not fail with an error code of EINTR.

Block on a condition variable. The application shall ensure that this function is called with mutex locked by the calling thread; otherwise, an error (for mutex::type::errorcheck and robust mutexes) or undefined behaviour (for other mutexes) results.

These functions atomically release mutex and cause the calling thread to block on the condition variable; atomically here means "atomically with respect to access by another thread to the mutex and then the condition variable". That is, if another thread is able to acquire the mutex after the about-to-block thread has released it, then a subsequent call to broadcast() or signal() in that thread shall behave as if it were issued after the about-to-block thread has blocked.

Upon successful return, the mutex shall have been locked and shall be owned by the calling thread. If mutex is a robust mutex where an owner terminated while holding the lock and the state is recoverable, the mutex shall be acquired even though the function returns an error code.

When using condition variables there is always a Boolean predicate involving shared variables associated with each condition wait that is true if the thread should proceed. Spurious wakeups from the wait() functions may occur. Since the return from wait() does not imply anything about the value of this predicate, the predicate should be re-evaluated upon such return.

When a thread waits on a condition variable, having specified a particular mutex to either the the wait() operation, a dynamic binding is formed between that mutex and condition variable that remains in effect as long as at least one thread is blocked on the condition variable. During this time, the effect of an attempt by any thread to wait on that condition variable using a different mutex is undefined. Once all waiting threads have been unblocked (as by the broadcast() operation), the next wait operation on that condition variable shall form a new dynamic binding with the mutex specified by that wait operation. Even though the dynamic binding between condition variable and mutex may be removed or replaced between the time a thread is unblocked from a wait on the condition variable and the time that it returns to the caller or begins cancellation cleanup, the unblocked thread shall always re-acquire the mutex specified in the condition wait operation call from which it is returning.

A condition wait (whether timed or not) is a cancellation point. When the cancellability type of a thread is set to PTHREAD_CANCEL_DEFERRED, a side-effect of acting upon a cancellation request while in a condition wait is that the mutex is (in effect) re-acquired before calling the first cancellation cleanup handler. The effect is as if the thread were unblocked, allowed to execute up to the point of returning from the call to wait(), but at that point notices the cancellation request and instead of returning to the caller of wait(), starts the thread cancellation activities, which includes calling cancellation cleanup handlers.

A thread that has been unblocked because it has been cancelled while blocked in a call to wait() shall not consume any condition signal that may be directed concurrently at the condition variable if there are other threads blocked on the condition variable.

Warning
Cannot be invoked from Interrupt Service Routines.
POSIX compatibility
Inspired by pthread_cond_wait() from <pthread.h> (IEEE Std 1003.1, 2013 Edition).

Definition at line 506 of file os-condvar.cpp.


The documentation for this class was generated from the following files: