###  | # Boost.Threads ## condition

Introduction
Header
Synopsis
Members
Example

## Introduction

An object of class `condition` is a synchronization primitive used to cause a thread to wait until a particular shared-data condition (or time) is met. A `condition` object is always used in conjunction with a mutex object modeling a Mutex Concept. The mutex must be locked prior to waiting on the `condition`, which is ensured by passing a lock object modeling a Lock Concept to the `condition` object's `wait` functions. While the thread is waiting on the `condition` object, the mutex associated with the lock is unlocked. When the thread returns from a call to one of the `condition` object's `wait` functions, the mutex is again locked. The tricky lock/unlock/lock sequence is performed automatically by the `condition` object's `wait` functions.

The `condition` type is often used to implement the Monitor Object and other important patterns. See [Schmidt-00] and [Hoare 74]. Monitors are one of the most important patterns for creating reliable multithreaded programs.

See Formal Definitions for definitions of thread states blocked and ready. Note that "waiting" is a synonym for blocked.

## Header

    #include <boost/thread/condition.hpp>

## Synopsis

    namespace boost {

    class condition : private boost::noncopyable // Exposition only.
       // Class condition meets the NonCopyable requirement.
    {
    public:
       condition();
       ~condition();

       void notify_one();
       void notify_all();
       template <typename ScopedLock>
          void wait(ScopedLock& lock);
       template <typename ScopedLock, typename Predicate>
          void wait(ScopedLock& lock, Predicate pred);
       template <typename ScopedLock>
          bool timed_wait(ScopedLock& lock, const xtime& xt);
       template <typename ScopedLock, typename Predicate>
          bool timed_wait(ScopedLock& lock, const xtime& xt, Predicate pred);
    };

    } // namespace boost

## Members

### Constructor

    condition();

Effects: Constructs a `condition`.

### Destructor

    ~condition();

Effects: Destroys `*this`.

### notify_one

    void notify_one();

Effects: If there is a thread waiting on `*this`, change that thread's state to ready. Otherwise there is no effect.

Notes: If more that one thread is waiting on the condition, it is unspecified which is made ready.

### notify_all

    void notify_all();

Effects: Change the state of all threads waiting on `*this` to ready. If there are no waiting threads, `notify_all()` has no effect.

### wait

    template <typename ScopedLock>
       void wait(ScopedLock& lock);

Requires: ScopedLock meets the ScopedLock requirements.

Effects: Releases the lock on the mutex model associated with `lock`, blocks the current thread of execution until readied by a call to `this->notify_one()` or `this->notify_all()`, and then reacquires the lock. All effects occur in an atomic fashion.

Throws: `lock_error` if `!lock.locked()`

Danger: This version should always be used within a loop checking that the state logically associated with the `condition` has become true. Without the loop, race conditions can ensue due to possible "spurious wake ups". The second version encapsulates this loop idiom internally and is generally the preferred method.

    template <typename ScopedLock, typename Pr>
       void wait(ScopedLock& lock, Pr pred);

Requires: ScopedLock meets the ScopedLock requirements, return from `pred()` convertible to bool.

Effects: As if:

`while (!pred()) wait(lock)`

Throws: `lock_error` if `!lock.locked()`

### timed_wait

    template <typename ScopedTimedLock>
       bool timed_wait(ScopedTimedLock& lock, const xtime& xt);

Requires: ScopedTimeLock meets the ScopedTimedLock requirements.

Effects: Releases the lock on the mutex model associated with the `lock`, blocks the current thread of execution until readied by a call to `this->notify_one()` or `this->notify_all()`, or until `xt`, and then reacquires the lock. All effects occur in an atomic fashion.

Throws: `lock_error` if `!lock.locked()`

Danger: This version should always be used within a loop checking that the state logically associated with the `condition` has become true. Without the loop, race conditions can ensue due to "spurious wake ups". The second version encapsulates this loop idiom internally and is generally the preferred method.

Returns: `false` if `xt` is reached, otherwise `true`.

    template <typename ScopedTimedLock, typename Pr>
       bool timed_wait(ScopedTimedLock& lock, const xtime& xt, Pr pred);

Requires: ScopedTimeLock meets the ScopedTimedLock requirements, return from `pred()` convertible to bool.

Effects: As if:

`while (!pred())
{
if (!timed_wait(lock, xt))
return false;
}`

Throws: `lock_error` if `!lock.locked()`

Returns: `false` if `xt` is reached, otherwise `true`.

## Example Usage

    #include <iostream>
    #include <vector>
    #include <boost/utility.hpp>
    #include <boost/thread/condition.hpp>
    #include <boost/thread/thread.hpp>

    class bounded_buffer : private boost::noncopyable
    {
    public:
        typedef boost::mutex::scoped_lock lock;

        bounded_buffer(int n) : begin(0), end(0), buffered(0), circular_buf(n) { }

        void send (int m) {
            lock lk(monitor);
            while (buffered == circular_buf.size())
                buffer_not_full.wait(lk);
            circular_buf[end] = m;
            end = (end+1) % circular_buf.size();
            ++buffered;
            buffer_not_empty.notify_one();
        }
        int receive() {
            lock lk(monitor);
            while (buffered == 0)
                buffer_not_empty.wait(lk);
            int i = circular_buf[begin];
            begin = (begin+1) % circular_buf.size();
            --buffered;
            buffer_not_full.notify_one();
            return i;
        }

    private:
        int begin, end, buffered;
        std::vector<int> circular_buf;
        boost::condition buffer_not_full, buffer_not_empty;
        boost::mutex monitor;
    };

    bounded_buffer buf(2);

    void sender() {
        int n = 0;
        while (n < 100) {
           buf.send(n);
           std::cout << "sent: " << n << std::endl;
           ++n;
        }
        buf.send(-1);
    }

    void receiver() {
        int n;
        do {
           n = buf.receive();
           std::cout << "received: " << n << std::endl;
        } while (n != -1); // -1 indicates end of buffer
    }

    int main(int, char*[])
    {
        boost::thread thrd1(&sender);
        boost::thread thrd2(&receiver);
        thrd1.join();
        thrd2.join();
        return 0;
    }

Typical output (dependent on scheduling policies) is:

    sent: 0
    sent: 1
    received: 0
    received: 1
    sent: 2
    sent: 3
    received: 2
    received: 3
    sent: 4
    received: 4

Revised 01 October, 2001

© Copyright William E. Kempf 2001 all rights reserved.