30 Thread support library [thread]

30.5 Condition variables [thread.condition]

30.5.2 Class condition_variable_any [thread.condition.condvarany]

A Lock type shall meet the BasicLockable requirements ([thread.req.lockable.basic]). [ Note: All of the standard mutex types meet this requirement. If a Lock type other than one of the standard mutex types or a unique_lock wrapper for a standard mutex type is used with condition_variable_any, the user must ensure that any necessary synchronization is in place with respect to the predicate associated with the condition_variable_any instance.  — end note ]

namespace std {
  class condition_variable_any {
  public:
    condition_variable_any();
    ~condition_variable_any();

    condition_variable_any(const condition_variable_any&) = delete;
    condition_variable_any& operator=(const condition_variable_any&) = delete;

    void notify_one() noexcept;
    void notify_all() noexcept;
    template <class Lock>
      void wait(Lock& lock);
    template <class Lock, class Predicate>
      void wait(Lock& lock, Predicate pred);

    template <class Lock, class Clock, class Duration>
      cv_status wait_until(Lock& lock, const chrono::time_point<Clock, Duration>& abs_time);
    template <class Lock, class Clock, class Duration, class Predicate>
      bool wait_until(Lock& lock, const chrono::time_point<Clock, Duration>& abs_time,
        Predicate pred);
    template <class Lock, class Rep, class Period>
      cv_status wait_for(Lock& lock, const chrono::duration<Rep, Period>& rel_time);
    template <class Lock, class Rep, class Period, class Predicate>
      bool wait_for(Lock& lock, const chrono::duration<Rep, Period>& rel_time,
        Predicate pred);
  };
}

condition_variable_any();

Effects: Constructs an object of type condition_variable_any.

Throws: bad_alloc or system_error when an exception is required ([thread.req.exception]).

Error conditions:

  • resource_unavailable_try_again — if any native handle type manipulated is not available.

  • operation_not_permitted — if the thread does not have the privilege to perform the operation.

~condition_variable_any();

Requires: There shall be no thread blocked on *this. [ Note: That is, all threads shall have been notified; they may subsequently block on the lock specified in the wait. This relaxes the usual rules, which would have required all wait calls to happen before destruction. Only the notification to unblock the wait must happen before destruction. The user must take care to ensure that no threads wait on *this once the destructor has been started, especially when the waiting threads are calling the wait functions in a loop or using the overloads of wait, wait_for, or wait_until that take a predicate.  — end note ]

Effects: Destroys the object.

void notify_one() noexcept;

Effects: If any threads are blocked waiting for *this, unblocks one of those threads.

void notify_all() noexcept;

Effects: Unblocks all threads that are blocked waiting for *this.

template <class Lock> void wait(Lock& lock);

Note: if any of the wait functions exits via an exception, it is unspecified whether the Lock is held. One can use a Lock type that allows to query that, such as the unique_lock wrapper.

Effects:

  • Atomically calls lock.unlock() and blocks on *this.

  • When unblocked, calls lock.lock() (possibly blocking on the lock) and returns.

  • The function will unblock when signaled by a call to notify_one(), a call to notify_all(), or spuriously.

  • If the function exits via an exception, lock.lock() shall be called prior to exiting the function scope.

Postcondition: lock is locked by the calling thread.

Throws: system_error when an exception is required ([thread.req.exception]).

Error conditions:

  • equivalent error condition from lock.lock() or lock.unlock().

template <class Lock, class Predicate> void wait(Lock& lock, Predicate pred);

Effects:

while (!pred())
  wait(lock);

template <class Lock, class Clock, class Duration> cv_status wait_until(Lock& lock, const chrono::time_point<Clock, Duration>& abs_time);

Effects:

  • Atomically calls lock.unlock() and blocks on *this.

  • When unblocked, calls lock.lock() (possibly blocking on the lock) and returns.

  • The function will unblock when signaled by a call to notify_one(), a call to notify_all(), expiration of the absolute timeout ([thread.req.timing]) specified by abs_time, or spuriously.

  • If the function exits via an exception, lock.lock() shall be called prior to exiting the function scope.

Postcondition: lock is locked by the calling thread.

Returns: cv_status::timeout if the absolute timeout ([thread.req.timing]) specified by abs_time expired, otherwise cv_status::no_timeout.

Throws: system_error when an exception is required ([thread.req.exception]).

Error conditions:

  • equivalent error condition from lock.lock() or lock.unlock().

template <class Lock, class Rep, class Period> cv_status wait_for(Lock& lock, const chrono::duration<Rep, Period>& rel_time);

Effects: as if

return wait_until(lock, chrono::steady_clock::now() + rel_time);

Returns: cv_status::timeout if the relative timeout ([thread.req.timing]) specified by rel_time expired, otherwise cv_status::no_timeout.

Postcondition: lock is locked by the calling thread.

Throws: system_error when an exception is required ([thread.req.exception]).

Error conditions:

  • equivalent error condition from lock.lock() or lock.unlock().

template <class Lock, class Clock, class Duration, class Predicate> bool wait_until(Lock& lock, const chrono::time_point<Clock, Duration>& abs_time, Predicate pred);

Effects:

while (!pred())
  if (wait_until(lock, abs_time) == cv_status::timeout)
    return pred();
return true;

Returns: pred()

Note: The returned value indicates whether the predicate evaluates to true regardless of whether the timeout was triggered.  — end note ]

template <class Lock, class Rep, class Period, class Predicate> bool wait_for(Lock& lock, const chrono::duration<Rep, Period>& rel_time, Predicate pred);

Effects: as if

return wait_until(lock, chrono::steady_clock::now() + rel_time, std::move(pred));

Note: There is no blocking if pred() is initially true, even if the timeout has already expired.  — end note ]

Postcondition: lock is locked by the calling thread.

Returns: pred()

Note: The returned value indicates whether the predicate evaluates to true regardless of whether the timeout was triggered.  — end note ]

Throws: system_error when an exception is required ([thread.req.exception]).

Error conditions:

  • equivalent error condition from lock.lock() or lock.unlock().