Showing posts with label Concurrency. Show all posts
Showing posts with label Concurrency. Show all posts

Friday, February 28, 2025

Lock free programming

Overview
The atomic classes which provide synchronization thru interlocked atomic operations.

Details
atomic
An atomic class is template based and its instances are guaranteed to be thread safe during access, updates.  
Certain POD types are also supported.
Specialization classes are defined for scalar data types such as boolean, integers, floating point, pointers etc, which provide additional atomic arithmetic and logical operations.
Additionally, atomic objects have the ability to synchronize access to other non-atomic objects in their threads by specifying different memory orders.

syntax
template< class T >
struct atomic
//specialization for pointers
template< class U >
struct atomic<U*>

member types
NameDescription
value_typeTemplate parameter - type of the data

constructors
NameDescription
  1. atomic()
  2. atomic (T val
  1. Default constructor
  2. Initialization constructor

overloaded operators
NameDescription
 T operator= (T val)Atomically replaces the value with val.
operator T()Atomically loads and returns the current value of the atomic variable. Equivalent to load().

atomic<> derivative data types are declared as below.
atomic<int> i=5;
atomic_int j=10;
 
memory order
load(), store() and exchange() APIs also accept additional parameter for accepting memory order.  It must be one of the following below.
OrderDescription
memory_order_relaxed         There are no synchronization or ordering constraints imposed on other reads or writes, only this operation's atomicity is guaranteed
memory_order_consume      A load operation with this memory order performs a consume operation on the affected memory location: no reads or writes in the current thread dependent on the value currently loaded can be reordered before this load. Writes to data-dependent variables in other threads that release the same atomic variable are visible in the current thread. On most platforms, this affects compiler optimizations only
memory_order_acquire       A load operation with this memory order performs the acquire operation on the affected memory location: no reads or writes in the current thread can be reordered before this load. All writes in other threads that release the same atomic variable are visible in the current thread
memory_order_release     A store operation with this memory order performs the release operation: no reads or writes in the current thread can be reordered after this store. All writes in the current thread are visible in other threads that acquire the same atomic variable and writes that carry a dependency into the atomic variable become visible in other threads that consume the same atomic.
memory_order_acq_relA read-modify-write operation with this memory order is both an acquire operation and a release operation. No memory reads or writes in the current thread can be reordered before the load, nor after the store. All writes in other threads that release the same atomic variable are visible before the modification and the modification is visible in other threads that acquire the same atomic variable.
memory_order_seq_cst                                                                                                                                      A load operation with this memory order performs an acquire operation, a store performs a release operation, and read-modify-write performs both an acquire operation and a release operation, plus a single total order exists in which all threads observe all modifications in the same order.

methods
The following are general methods available to instances.
NameDescription
bool is_lock_free()Checks if the atomic object is lock-free
void store
(T desired, memory_order order = memory_order_seq_cst )
Atomically replaces the value of the atomic object with a non-atomic argument. Memory is affected according to the value of order which can be any of memory_order_relaxed, memory_order_release, memory_order_seq_cst
T load
(memory_order order = memory_order_seq_cst )
Atomically obtains the value of the atomic object. Memory is affected according to the value of order which can be any of memory_order_relaxed, memory_order_consume, memory_order_acquire, memory_order_seq_cst.
T exchange
( T desired, memory_order order = memory_order_seq_cst )
Atomically replaces the value of the atomic object and obtains the value held previously.
The entire operation is atomic (an atomic read-modify-write operation): the value is not affected by other threads between the instant its value is read (to be returned) and the moment it is modified by this function.
Memory is affected according to the value of order which can be any of memory_order_relaxed, memory_order_consume, memory_order_acquire, memory_order_release, memory_order_acq_rel, memory_order_seq_cst.
  1. bool compare_exchange_weak
     (T& expected, T desired,
    memory_order success,  memory_order failure) 
  2. bool compare_exchange_weak
     (T& expected, T desired,
    memory_order order =   memory_order_seq_cst
Compares the contents of the atomic object's contained value with expected:
- if true, it replaces the contained value with val (like store).
- if false, it replaces expected with the contained value .

The function always accesses the contained value to read it, and -if the comparison is true- it then also replaces it. But the entire operation is atomic: the value cannot be modified by other threads between the instant its value is read and the moment it is replaced.

The memory order used in the 1st overload depends on the result of the comparison: if true, it uses success; if false, it uses failure.
In the 2nd overload, memory is affected according to the value of order.

Unlike compare_exchange_strong, this weak version is allowed to fail spuriously by returning false even when expected indeed compares equal to the contained object. This may be acceptable behavior for certain looping algorithms, and may lead to significantly better performance on some platforms. On these spurious failures, the function returns false while not modifying expected.

For non-looping algorithms, compare_exchange_strong is generally preferred.
  1. bool compare_exchange_strong
    (T& expected, T desired,
    memory_order success, memory_order failure ) 
  2. bool compare_exchange_strong
    (T& expected, T desired,
    memory_order order = memory_order_seq_cst
Behave same as compare_exchange_weak().

Unlike compare_exchange_weak(), this strong version is required to always return true when expected indeed compares equal to the contained object, not allowing spurious failures. However, on certain platforms, and for certain algorithms that check this in a loop, compare_exchange_weak may lead to significantly better performance.

The following methods are defined for atomic class specialization for pointers.
NameDescription

T fetch_add
(ptrdiff_t val, memory_order sync = memory_order_seq_cst
Similar to += operation. Atomically adds val to the contained value and returns the previous value  immediately before the operation.
Memory is affected according to the value of sync.
T fetch_sub
(ptrdiff_t val, memory_order sync = memory_order_seq_cst
Similar to -= operation. Atomically subtracts val to the contained value and returns the previous value  immediately before the operation.
Memory is affected according to the value of sync.
T operator+= (ptrdiff_t val) Same as fecth_add.
T operator-= (ptrdiff_t val) Same as fecth_sub.
T operator++() 
operator++ (int)
Same as pre and post increment operations for integral types.
T operator--() 
T operator-- (int)
Same as pre and post decrement operations for integral types.

The following methods are defined for atomic class specialization for floating  types.
NameDescription
T fetch_add
(T val, memory_order sync = memory_order_seq_cst)
Similar to += operation. Atomically adds val to the contained value and returns the previous value  immediately before the operation.
Memory is affected according to the value of sync.
T fetch_sub
(T val, memory_order sync = memory_order_seq_cst)
Similar to -= operation. Atomically subtracts val to the contained value and returns the previous value  immediately before the operation.
Memory is affected according to the value of sync.

The following methods are defined for atomic class specialization for integral types.
NameDescription
T fetch_add
(T val, memory_order sync = memory_order_seq_cst)
Similar to += operation. Atomically adds val to the contained value and returns the previous value  immediately before the operation.
Memory is affected according to the value of sync.
T fetch_sub
(T val, memory_order sync = memory_order_seq_cst)
Similar to -= operation. Atomically subtracts val to the contained value and returns the previous value  immediately before the operation.
Memory is affected according to the value of sync.
T fetch_and
(T val, memory_order  sync = memory_order_seq_cst
Atomically performs bitwise AND between the argument and the value of the atomic object and obtains the value held previously.
Memory is affected according to the value of sync.
T fetch_or
(T val, memory_order sync = memory_order_seq_cst
Atomically performs bitwise OR between the argument and the value of the atomic object and obtains the value held previously.
Memory is affected according to the value of sync.
T fetch_xor
(T val, memory_order sync = memory_order_seq_cst
atomically performs bitwise XOR between the argument and the value of the atomic object and obtains the value held previously.
Memory is affected according to the value of sync.
T operator++() 
T operator++ (int) 
  1. Pre Increments the value of the contained value and returns the resulting contained value 
  2. Post Increments the value of the contained value and returns the previous value it had immediately before the operation.
The entire operation is atomic: the value cannot be modified between the instant its value is read and the moment it is modified by this function.
T operator--() 
T operator-- (int)
  1. Pre decrements the value of the contained value and returns the resulting contained value 
  2. Post decrements the value of the contained value and returns the previous value it had immediately before the operation.
The entire operation is atomic: the value cannot be modified between the instant its value is read and the moment it is modified by this function.
T operator+= (T val) Same as fecth_add.
T operator-= (T val) Same as fecth_sub.
T operator&= (T val)Same as operator and.
T operator|= (T val)Same as operator or.
T operator^= (T val)Same as operator xor.

This  example 20  demonstrates the functionality of the atomics<> as seen in its console output.  
It defines a critical_section based on atomic<bool> that can be used to synchronize threads like a mutex. It also defines a stack that can be used by multiple threads  for access and updates.

This example 21  demonstrates the functionality of the atomic<> as seen in its console output. 
The main thread spawns two worker threads to print numbers serially. Synchronization is provided by a atomic<int>.

atomic_flag 
atomic_flag is an atomic boolean type. Unlike all specializations of  atomic<>, it is guaranteed to be lock-free and also it does not provide load() or store() operations.
constructors
NameDescription
  1. atomic_flag()
  2. atomic_flag(val
  1. Default constructor
  2. Initialization constructor

atomic_flag  supports following operations.
NameDescription
void clear
(memory_order order =              memory_order_seq_cst )
Atomically sets flag to false. Memory is affected according to the value of order which can be any of memory_order_relaxedmemory_order_releasememory_order_seq_cst
bool test_and_set
(memory_order order = memory_order_seq_cst)
Atomically sets the flag to true and obtains its previous value. Memory is affected according to the value of order which can be any of memory_order_relaxed, memory_order_consume, memory_order_acquire, memory_order_release, memory_order_acq_rel, memory_order_seq_cst.

This example 22  demonstrates the functionality of the atomic_flag as seen in its console output. 
It defines a critical_section based on atomic<bool> that can be used to synchronize threads like a mutex. It also defines a stack that can be used by multiple threads  for access and updates.

Synchronization Utility Classes and functions

Overview
These classes provide wrapper for Synchronization classes.

Details
The following discusses these new features in detail.

tag classes
The following empty class tag types can be used in the constructor's parameter list for lock_guard, unique_lock and shared_lock to specify locking strategy.
struct defer_lock_t { explicit defer_lock_t() = default; }
struct try_to_lock_t { explicit try_to_lock_t() = default; }
struct adopt_lock_t { explicit adopt_lock_t() = default; }

The following predefined instances of the above classes  can be passed to the constructors to indicate the type of locking strategy.
defer_lock_t defer_lock {};
try_to_lock_t try_to_lock {};
adopt_lock_t adopt_lock {};

The following table describes the effect of each tag.
NameDescription
defer_lock_tdo not acquire ownership of the mutex
try_to_lock_ttry to acquire ownership of the mutex without blocking
adopt_lock_tassume the calling thread already has ownership of the mutex

lock_guard
lock_guard is a RAII-style object for owning a mutex for the duration of a scoped block.

syntax
// Mutex - the type of the mutex to lock
template< class Mutex >
class lock_guard

member types
NameDescription
mutex_typeTemplate parameter - type of the mutex

constructors
NameDescription
  1. lock_guard
    (mutex_type& m)
  2. lock_guard
    (mutex_type& m, adopt_lock_t tag)
  1. Gets ownership of mutex by calling lock() on it.
  2. Gets  ownership of mutex without calling lock() on it. The tag parameter used to select non-locking version of the constructor.

When a lock_guard object is created, it attempts to take ownership of the mutex it is given. When control leaves the scope in which the lock_guard object was created, the lock_guard is destructed and the mutex is released.

The following code use of the lock_guard. The commented code shows how mutex is locked and unlocked without lock_guard. Whereas a single instantiation of lock_guard removes the need for explicit lock() and unlock() calls.
mutex m;

//{
//	m.lock();
//	cout << "inside"
//	m.unlock();
//}

{
	lock_guard<mutex> lg(m);
	cout << "inside"
}

unique_lock
unique_lock is similar to lock_guard with extended functionality allowing deferred locking, time-constrained attempts at locking, recursive locking, transfer of lock ownership, and use with condition variables.

syntax
// Mutex - the type of the mutex to lock
template< class Mutex >
class unique_lock

member types
NameDescription
mutex_typeTemplate parameter - type of the mutex

constructors
NameDescription
  1. unique_lock()
  2. unique_lock
    (unique_lock&& other) 
  3. unique_lock
    (mutex_type& m)
  4. unique_lock
    (mutex_type& m, defer_lock_t t) 
  5. unique_lock
    (mutex_type& m, try_to_lock_t t)
  6. unique_lock
    (mutex_type& m, adopt_lock_t t)
  7. unique_lock
    (mutex_type& m, duration d)
  8. unique_lock
    (mutex_type& m, time_point tp)
  1. Default constructor
  2. Move constructor
  3. Locks the associated mutex by calling m.lock().
  4. Does not lock the associated mutex.
  5. Tries to lock the associated mutex without blocking by calling m.try_lock(). 
  6. Assumes the calling thread already holds a non-shared lock (i.e., a lock acquired by lock, try_lock, try_lock_for, or try_lock_until) on m. 
  7. Tries to lock the associated mutex by calling m.try_lock_for(timeout_duration). Blocks until specified timeout_duration has elapsed or the lock is acquired, whichever comes first. The mutex_type should be a timed_mutex.
  8. Tries to lock the associated mutex by calling m.try_lock_until(timeout_time). Blocks until specified timeout_time has been reached or the lock is acquired, whichever comes first. The mutex_type should be a timed_mutex.

methods
The following are commonly used methods:
NameDescription
void lock()Tries to lock the associated mutex
bool try_lock()Tries to lock the associated mutex without blocking
bool try_lock_for
(duration d)
Attempts to lock the associated timed_mutex, while waiting for a time span.
bool try_lock_until
(time_point tp)
Attempts to lock the associated timed_mutex, while waiting for a time point.
void unlock()Unlocks  the associated mutex.
mutex_type * release()Disassociates the associated mutex without unlocking it. Returns a pointer to the managed mutex object, releasing ownership over it.
mutex_type * mutex()Returns a pointer to the associated mutex. 
bool owns_lock()Tests whether the lock owns its associated mutex.
operator bool()Tests whether the lock owns its associated mutex

This example 13  demonstrates the functionality of the unique_lock as seen in 
its console output. 

shared_lock
shared_lock is similar to unique_lock except it can be used with condition_variable_any.
The difference between them is that shared_lock is designed to support readers in a read/write lock. It can have multiple threads to acquire the shared lock and reading the same data, but to write to the data,  lock should be used to get permission to write to the data.
syntax
// Mutex - the type of the mutex to lock
template< class Mutex >
class shared_lock
member types
NameDescription
mutex_typeTemplate parameter - type of the mutex

constructors
NameDescription
  1. shared_lock()
  2. shared_lock
    (shared_lock&& other) 
  3. shared_lock
    (mutex_type& m)
  4. shared_lock
    (mutex_type& m, defer_lock_t t) 
  5. shared_lock
    (mutex_type& m, try_to_lock_t t)
  6. shared_lock
    (mutex_type& m, adopt_lock_t t)
  7. shared_lock
    (mutex_type& m, duration d)
  8. shared_lock
    (mutex_type& m, time_point tp)
  1. Default constructor
  2. Move constructor
  3. Locks the associated mutex by calling m.lock().
  4. Does not lock the associated mutex.
  5. Tries to lock the associated mutex without blocking by calling m.try_lock(). 
  6. Assumes the calling thread already holds a non-shared lock (i.e., a lock acquired by lock, try_lock, try_lock_for, or try_lock_until) on m. 
  7. Tries to lock the associated mutex by calling m.try_lock_for(timeout_duration). Blocks until specified timeout_duration has elapsed or the lock is acquired, whichever comes first. The mutex_type should be a timed_mutex.
  8. Tries to lock the associated mutex by calling m.try_lock_until(timeout_time). Blocks until specified timeout_time has been reached or the lock is acquired, whichever comes first. The mutex_type should be a timed_mutex.

methods
The following are commonly used methods:
NameDescription
void lock()Tries to lock the associated mutex
bool try_lock()Tries to lock the associated mutex without blocking
bool try_lock_for
(duration d)
Attempts to lock the associated timed_mutex, while waiting for a time span.
bool try_lock_until
(time_point tp)
Attempts to lock the associated timed_mutex, while waiting for a time point.
void unlock()Unlocks  the associated mutex.
mutex_type * release()Disassociates the associated mutex without unlocking it. Returns a pointer to the managed mutex object, releasing ownership over it.
mutex_type * mutex()Returns a pointer to the associated mutex. 
bool owns_lock()Tests whether the lock owns its associated mutex.
operator bool()Tests whether the lock owns its associated mutex

This example 13  demonstrates the functionality of the shared_lock as seen in 
its console output. 

lock()
lock is a template function that can be used to lock multiple lockable objects.
syntax
//lockables such as mutex  
template< class Lockable, class Lockable2, class... LockableN >
void lock( Lockable& lock, Lockable2& lock2, LockableN&... lockn )

lock enables locking multiple mutexes without deadlocking. When the lock succeeds the thread owns the mutexes. After locking, mutexes must be also unlocked after use. 
This can be done by using adoption_lock  as below
mutex m, m2;
 
lock(m, m2);
unique_lock<mutex> lk(m, adopt_lock);
unique_lockmutex> lk2(m2, adopt_lock);

or by using defer_lock as below. Notice the difference in the arguments type passed to lock() call.
mutex m, m2;
 
unique_lock<mutex> lk(m, defer_lock);
unique_lock<mutex> lk2(m2, defer_lock);
lock(lk, lk2);

This example 14  demonstrates the functionality of the lock as seen in its console output. Synchronization is provided by a mutex and lock.

A restaurant has 2 tables(T, T2) and 2 waiters(W, W2) with a service time of 3 seconds. Initially the main thread spawns four threads assigning waiters and tables. i.e., TW,  TW2, T2W, T2W2. The tables and waiters are protected by a mutex. The assignment algorithm waits on both table and waiter mutexes to make assignments.

This example 15  demonstrates the functionality of the unique_lock as seen in its console output. Synchronization is provided by a  unique_lock  and mutex.
The program tries to transfer money from sam_acct to rob_acct, steve_acct.

Synchronization Classes and functions

Overview
These classes provide synchronization between Execution Classes.

Details
The following discusses these new features in detail.

mutex
Provides synchronization to access to a shared resource from multiple threads. The following commonly used methods.

member types
NameDescription
native_handle_typeimplementation-defined

constructors
NameDescription
mutex() Default constructor. The object will be in an unlocked state.

methods
NameDescription
void lock()Locks the mutex on the calling thread. Blocks if the mutex is already locked in a different thread. It causes deadlock if called twice on the same thread.
void unlock()Unlocks the mutex Note that a mutex can be unlocked from a different thread. The counts of lock and unlock should match.
bool try_lock()Tries to lock the mutex, returns if the mutex is not available.
native_handle_type native_handle()Returns the underlying implementation-defined native handle object

This example 10   demonstrates the functionality of the mutex as seen in its console output.
The main thread spawns two worker threads to print numbers serially. Synchronization is provided by a mutex.

timed_mutex
Similar to to a mutex. It also extends try_lock() as discussed below.

member types
NameDescription
native_handle_typeimplementation-defined

constructors
NameDescription
timed_mutex() Default constructor. The object will be in an unlocked state.

methods
NameDescription
void lock()Locks the mutex on the calling thread. Blocks if the mutex is already locked in a different thread. It causes deadlock if called twice on the same thread.
void unlock()Unlocks the mutex Note that a mutex can be unlocked from a different thread. The counts of lock and unlock should match.
bool try_lock()Tries to lock the mutex, returns if the mutex is not available.
native_handle_type 
native_handle()
Returns the underlying implementation-defined native handle object
bool try_lock_for
(duration d)
Tries to lock the mutex and waits for a time span.
bool try_lock_until
(time_point tp)
Tries to lock the mutex and waits for a time point.

This example 11  demonstrates the functionality of the timed_mutex as seen in its console outputSynchronization is provided by a timed_mutex.
The main thread owns the mutex, spawns a worker thread, sleeps for 3 seconds and unlocks the mutex. The worker thread waits to own the mutex for 5 seconds, print a message to the console. 

recursive_mutex
The owning thread of a mutex cannot call lock() again on it as it will be hung.  
recursive_mutex is same as mutex, except owning  thread can call lock() more than once. it must also call unlock() equal number of times.

member types
NameDescription
native_handle_typeimplementation-defined

constructors
NameDescription
recursive_mutex() Default constructor. The object will be in an unlocked state.

methods
NameDescription
void lock()Locks the mutex on the calling thread. Blocks if the mutex is already locked in a different thread. It does not cause deadlock if called more than once on the same thread.
void unlock()Unlocks the mutex Note that a mutex can be unlocked from a different thread. The counts of lock and unlock should match.
bool try_lock()Tries to lock the mutex, returns if the mutex is not available.
native_handle_type 
native_handle()
Returns the underlying implementation-defined native handle object

This example 12  demonstrates the functionality of the recursive_mutex as seen in 
its console output. Synchronization is provided by a recursive_mutex.
The program defines 3 methods create_table_withoutdata(), insert_data() and create_table_withdata(). All these methods locks the mutex and releases it after work. 
create_table_withdata(method internally calls insert_data() thus mutex is locked twice and unlocked twice.

recusrisve_timed_mutex
Combines functionalities of recursive_mutex and timed_mutex.

member types
NameDescription
native_handle_typeimplementation-defined

constructors
NameDescription
recursive_timed_mutex() Default constructor. The object will be in an unlocked state.

methods
NameDescription
void lock()Locks the mutex on the calling thread. Blocks if the mutex is already locked in a different thread.  It does not cause deadlock if called twice on the same thread.
void unlock()Unlocks the mutex Note that a mutex can be unlocked from a different thread. The counts of lock and unlock should match.
bool try_lock()Tries to lock the mutex, returns if the mutex is not available.
native_handle_type 
native_handle()
Returns the underlying implementation-defined native handle object
bool try_lock_for
(duration d)
Tries to lock the mutex and waits for a time span.
bool try_lock_until
(time_point tp)
Tries to lock the mutex and waits for a time point.

cv_status

enum class cv_status { no_timeout, timeout };
enum class whose values are returned by the wait_for() and wait_until() members of condition_variable and condition_variable_any.

NameDescription
no_timeout Function returned without time out, possibly due to notification.
timeoutFunction returned due to Time out.

conditional_variable
conditinal_variable removes the need for polling and idling during producer-consumer scenarios.

constructors
NameDescription
conditional_variable() Default constructor. 

In order to work, conditinal_variable require a mutex and unique_lock. Optionally a boolean variable to prevent spurious wake ups.
mutex cvmtx;
condition_variable cv;
bool condtion=false;

The following depicts  typical scenario. However multiple variations can be applied.
One or more  consumer threads waits on a condition_variable with a callable object checking for a condition to be true as below.
void consumer()
{
    unique_lock<mutex> lk(cvmtx);
    cv.wait(lk,[](){return condition;});
}

The producer signals the waiting consumer thread(s)  with notify_one() or notify_all() call as below. 
This will wake up the waiting consumer thread(s) from wait.
void producer()
{
    lock_guard(cvmtx);
    condition = true;
    cv.notify_one();
}

The following lists important apis
NameDescription
void notify_one()notifies one waiting thread
void notify_all()notifies all waiting threads
  1. void wait
    (unique_lock l)
  2. cv_status wait
    (unique_lock l, Predicate pred)
Blocks the current thread until the condition variable is awakened.
To prevent spurious wakeups, the 2nd version is implemented as below.
while (!pred()) wait(lck);
  1. void wait_for
    (unique_lock l, duration d)
  2. cv_status wait
    (unique_lock l, duration d, Predicate pred)
Blocks the current thread until the condition variable is awakened or after the specified timeout duration.
To prevent spurious wakeups, the 2nd version is implemented as below.
while (!pred()) wait_for(lck,d);
  1. void wait_until
    (unique_lock l, time_point tp)
  2. cv_status wait_until
    (unique_lock l, time_point tp, Predicate pred)
Blocks the current thread until the condition variable is awakened or until specified time point has been reached.
To prevent spurious wakeups, the 2nd version is implemented as below.
while (!pred()) wait_until(lck,tp);

This example 18   demonstrates the functionality of the conditinal_variable  as seen in its console output using thread.  Three chat clients, in three threads wait for message from chat server in a conditional variable.

conditional_variable_any
conditinal_variable_any is  similar to conditional_variable except its wait functions can take any lockable type such as shareed_lock as argument. Other than that, they are identical.

constructors
NameDescription
conditional_variable_any() Default constructor. 

In order to work, conditinal_variable_any require a mutex and lockable type such as unique_lock or shared_lock. Optionally a boolean variable to prevent spurious wake ups.
mutex cvmtx;
condition_variable cv;
bool condtion=false;

The following depicts  typical scenario. However multiple variations can be applied.
One or more  consumer threads waits on a conditinal_variable_any with a callable object checking for a condition to be true as below.
void consumer()
{
    unique_lock<mutex> lk(cvmtx);
    cv.wait(lk,[](){return condition;});
}

The producer signals the waiting consumer thread(s)  with notify_one() or notify_all() call as below. 
This will wake up the waiting consumer thread(s) from wait.
void producer()
{
    lock_guard(cvmtx);
    condition = true;
    cv.notify_one();
}

The following lists important apis
NameDescription
void notify_one()notifies one waiting thread
void notify_all()notifies all waiting threads
  1. void wait
    (unique_lock l)
  2. cv_status wait
    (unique_lock l, Predicate pred)
Blocks the current thread until the condition variable is awakened.
To prevent spurious wakeups, the 2nd version is implemented as below.
while (!pred()) wait(lck);
  1. void wait_for
    (unique_lock l, duration d)
  2. cv_status wait
    (unique_lock l, duration d, Predicate pred)
Blocks the current thread until the condition variable is awakened or after the specified timeout duration.
To prevent spurious wakeups, the 2nd version is implemented as below.
while (!pred()) wait_for(lck,d);
  1. void wait_until
    (unique_lock l, time_point tp)
  2. cv_status wait_until
    (unique_lock l, time_point tp, Predicate pred)
Blocks the current thread until the condition variable is awakened or until specified time point has been reached.
To prevent spurious wakeups, the 2nd version is implemented as below.
while (!pred()) wait_until(lck,tp);

This example 18   demonstrates the functionality of the conditinal_variable_any as seen in its console output using thread.  Three chat clients, in three threads wait for message from chat server in a conditional variable.


once_flag
Object of this type are used in call_once function.
struct once_flag 
{
    constexpr once_flag() noexcept;
    once_flag (const once_flag&) = delete;
    once_flag& operator= (const once_flag&) = delete;
}
Using the same object on different calls to call_once in different threads causes a single execution if called concurrently.

call_once()
Sometimes applications needs to initialize global variables or a instance of a class only once before it's accessed by multiple threads. It is usually done using a singleton with a lock. 

The call_once template function provides an alternative.
template< class Callable, class... Args >
void call_once( std::once_flag& flag, Callable&& f, Args&&... args );
flag - an object, for which exactly one function gets executed.
f - Executes the Callable object f exactly once, even if called concurrently from several threads.
args - Arguments to f.

Alternatively once_flag can be used. It involves declaring  a once_flag variable and initializing it using call_once() api as shown below. call_once() accepts a callable object. call_once() can be called from multiple threads but it's called only once. if the call fails due to an exception in one thread, it's tried again in another thread.
int balance=0;
std::once_flag balance_flag;
std::call_once(balance_flag, []()
{ 
	balance=1000;
});

This example 16  demonstrates the functionality of the once_flag  as seen in its console output using thread. 

The program defines three bank accounts sam_acct, rob_acct and steve_acct and tries to transfer money from sam_acct to rob_acct, steve_acct using multiple threads. once_flag  is used to initialize the balances. The first call to call_once() fails because of exception and the second succeeds. Third time it does not get called. 

This example 17  demonstrates the functionality of the once_flag  as seen in its console output using async. The functionality is same as Example 16.