Quick Links:

bal | bbl | bdl | bsl

Namespaces

Component bslmt_condition
[Package bslmt]

Provide a portable, efficient condition variable. More...

Namespaces

namespace  bslmt

Detailed Description

Outline
Purpose:
Provide a portable, efficient condition variable.
Classes:
bslmt::Condition portable intra-process signaling mechanism
See also:
Component bslmt_mutex
Description:
The bslmt::Condition class provided by this component implements the concept of a condition variable, enabling multiple threads to communicate information about the state of shared data. A condition variable is a signaling mechanism associated with a mutex, which in turn protects a data invariant. A condition variable enables threads to wait for a predicate (i.e., logical expression) to become true, and to communicate to other threads that the predicate might be true.
One or more threads can wait efficiently on a condition variable, either indefinitely or until some absolute time, by invoking one of the following methods of bslmt::Condition:
  int wait(bslmt::Mutex *mutex);
  int timedWait(bslmt::Mutex *mutex, const bsls::TimeInterval& absTime);
The caller must lock the mutex before invoking these functions. The bslmt::Condition atomically releases the lock and waits, thereby preventing other threads from changing the predicate after the lock is released, but before the thread begins to wait. The bslmt package guarantees that this lock will be reacquired before returning from a call to the wait and timedWait methods, unless an error occurs.
When invoking the timedWait method, clients must specify, via the parameter absTime, a timeout after which the call will return even if the condition is not signaled. absTime is expressed as a bsls::TimeInterval object that holds an absolute time according to the clock type the bslmt::Condition object is constructed with (the default clock is bsls::SystemClockType::e_REALTIME). Clients should use the bsls::SystemTime::now(clockType) utility method to obtain the current time.
Other threads can indicate that the predicate is true by signaling or broadcasting the same bslmt::Condition object. A broadcast wakes up all waiting threads, whereas a signal wakes only one thread. The client has no control over which thread will be signaled if multiple threads are waiting:
  void signal();
  void broadcast();
A thread waiting on a condition variable may be signaled (i.e., the thread may wake up without an error), but find that the predicate is still false. This situation can arise for a few reasons: spurious wakeups produced by the operating system, intercepted wakeups, and loose predicates. Therefore, a waiting thread should always check the predicate after (as well as before) the call to the wait function.
Supported Clock-Types:
bsls::SystemClockType supplies the enumeration indicating the system clock on which timeouts supplied to other methods should be based. If the clock type indicated at construction is bsls::SystemClockType::e_REALTIME, the absTime argument passed to the timedWait method should be expressed as an absolute offset since 00:00:00 UTC, January 1, 1970 (which matches the epoch used in bsls::SystemTime::now(bsls::SystemClockType::e_REALTIME). If the clock type indicated at construction is bsls::SystemClockType::e_MONOTONIC, the absTime argument passed to the timedWait method should be expressed as an absolute offset since the epoch of this clock (which matches the epoch used in bsls::SystemTime::now(bsls::SystemClockType::e_MONOTONIC).
Usage:
Suppose we have a bslmt::Condition object, condition, and a boolean predicate associated with condition (represented here as a free function that returns a bool value):
  bool predicate()
      // Return 'true' if the invariant holds for 'condition', and 'false'
      // otherwise.
  {
      return true;
  }
The following usage pattern should always be followed:
    // ...

    bslmt::Condition condition;
    bslmt::Mutex     mutex;

    mutex.lock();
    while (false == predicate()) {
        condition.wait(&mutex);
    }

    // Modify shared resources and adjust the predicate here.

    mutex.unlock();

    // ...
The usage pattern for a timed wait is similar, but has extra branches to handle a timeout:
    // ...

    enum { e_TIMED_OUT = -1 };
    bsls::TimeInterval absTime = bsls::SystemTime::nowRealtimeClock();

    // Advance 'absTime' to some delta into the future here.

    mutex.lock();
    while (false == predicate()) {
        const int status = condition.timedWait(&mutex, absTime);
        if (e_TIMED_OUT == status) {
            break;
        }
    }

    if (false == predicate()) {
        // The wait timed out and 'predicate' returned 'false'.  Perform
        // timeout logic here.

        // ...
    }
    else {
        // The condition variable was either signaled or timed out and
        // 'predicate' returned 'true'.  Modify shared resources and adjust
        // predicate here.

        // ...
    }
    mutex.unlock();

    // ...