CLX C++ Libraries - condition
Author: clown

CLX C++ Libraries
Home >> condition

# Declrations

    class condition;

# Overview

condition は，何らかの条件を基準にして，スレッド間で待受/通知制御を行うためのクラスです． 何らかの条件を満たせずに（読み込むためのデータが他のスレッドによってセットされていないなど）， それ以上処理を続けることができなくなった場合，wait() メソッドでスレッドの実行を一時休止して， 他のスレッドからの通知を待ち受けます．他のスレッドは自分の処理を続け， 休止したスレッドが処理を再開できる状態になれば，notify_one()，または notify_all() メソッドを用いてその旨を通知します．

# Example

example_condition.cpp

    #include <iostream>
    #include <sstream>
    #include <string>
    #include <list>
    #include "clx/thread.h"

    /* ------------------------------------------------------------------------- */
    //  trivial_queue
    /* ------------------------------------------------------------------------- */
    template <class Type>
    class trivial_queue {
    public:
        typedef Type value_type;

        trivial_queue() : list_(), mutex_(), not_empty_() {}
        virtual ~trivial_queue() {}

        void enqueue(const value_type& x) {
            clx::mutex::scoped_lock lock(mutex_);
            std::cout << "PSH: " << x << " (rest " << list_.size() << ")" << std::endl;
            list_.push_back(x);
            not_empty_.notify_one();
        }

        value_type dequeue() {
            clx::mutex::scoped_lock lock(mutex_);
            while (list_.empty()) {
                std::cout << "empty buffer" << std::endl;
                not_empty_.wait(lock);
            }
            value_type tmp = list_.front();
            std::cout << "POP: " << tmp << " (rest " << list_.size() << ")" << std::endl;
            list_.pop_front();
            return tmp;
        }

        void reset() {
            clx::mutex::scoped_lock lock(mutex_);
            list_.clear();
        }

    private:
        std::list<value_type> list_;
        clx::mutex mutex_;
        clx::condition not_empty_;
    };

    trivial_queue<std::string> data_;
    clx::once_flag once_ = CLX_ONCE_INIT;

    /* ------------------------------------------------------------------------- */
    //  init_data
    /* ------------------------------------------------------------------------- */
    void init_data() {
        std::cout << "reset data queue" << std::endl;
        data_.reset();
    }

    /* ------------------------------------------------------------------------- */
    //  send_something
    /* ------------------------------------------------------------------------- */
    void send_something() {
        for (int i = 0; i < 10; i++) {
            clx::call_once(once_, init_data); // call_once test
            std::stringstream ss;
            ss << "element[" << i << "]";
            data_.enqueue(ss.str());
        }
    }

    /* ------------------------------------------------------------------------- */
    //  recv_something
    /* ------------------------------------------------------------------------- */
    void recv_something() {
        std::string s;
        for (int i = 0; i < 10; i++) {
            clx::call_once(once_, init_data); // call_once test
            s = data_.dequeue();
        }
    }

    /* ------------------------------------------------------------------------- */
    //  main
    /* ------------------------------------------------------------------------- */
    int main(int argc, char* argv[]) {
        clx::thread enq_th[2];
        clx::thread deq_th[2];

        // 第2引数がtrueの場合は，detach属性（joinで後処理を行う必要がない）
        for (size_t i = 0; i < 2; i++) enq_th[i].start(send_something, true);
        for (size_t i = 0; i < 2; i++) deq_th[i].start(recv_something, true);

        /*
         * detach属性の場合，作成したスレッドが仕事を終える前にメインスレッドが
         * 終了する可能性があるので，clx::exit(0)で待つ．
         */
        clx::exit(0);
    }

    Result
    reset data queue
    empty buffer
    empty buffer
    PSH: element[0] (rest 0)
    PSH: element[0] (rest 1)
    PSH: element[1] (rest 2)
    PSH: element[1] (rest 3)
    POP: element[0] (rest 4)
    PSH: element[2] (rest 3)
    POP: element[0] (rest 4)

    ・・・（以下略）・・・

# Related Types

    typedef ... handle_pointer;

# Construction and Member Functions

    condition();
    virtual ~condition();

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

    template <class LockT>
    bool timed_wait(LockT& lock, double sec);

    void notify_one();
    void notify_all();
    handle_pointer native_handle();

wait()，または timed_wait() メソッドには，mutex::scoped_lock，または recursive_mutex::scoped_lock を指定します．wait() メソッドは， 他のスレッドから通知があるまで待機し続けます．これに対して timed_wait() メソッドは， 最大でsec 秒まで待機します．timed_wait() メソッドは，タイムアウトした場合， false が返ります．

# Related Pages

1. CLX C++ Libraries - thread
2. CLX C++ Libraries - mutex
3. CLX C++ Libraries - call_once

# Reference

1. Life like a clown - マルチプラットフォームなスレッドクラス