Pebble Coding

ソフトウェアエンジニアによるIT技術、数学の備忘録

C++11でのcondition_variableを使ったマルチスレッド制御

#include <thread>
#include <mutex>
#include <queue>
#include <unistd.h> // usleep

using namespace std;

mutex print_mutex;  // printf()呼び出し排他用
mutex queue_mutex;  // v_queue排他アクセス用
queue<int> v_queue; // データキュー
condition_variable ready_cond; // 条件変数

void worker(void) {
    while (true) {
        int data;
        {
            // unique_lockではコンストラクタでロックを取得し、デストラクタでロックを解除する。
            // また、明示的にロック、アンロックが可能である。
            unique_lock<mutex> lk(queue_mutex);
            // キューにデータがない場合はキューにデータが追加されたことが
            // 通知されるまで待つ。CPUを余分に消費することがない。
            while (v_queue.empty()) {
                // waitを呼ぶ前にはlkがロック状態でなければならない。
                // C++11でもspurious wakeupの問題があることに注意。
                // ここでready_cond.notify_one()が呼ばれるまでブロックする。
                // ready_cond.notify_one()が呼ばれると、再びロックを取得した状態で、この関数から抜ける。
                ready_cond.wait(lk);
            }
            // キューからデータを取り出す
            data = v_queue.front();
            v_queue.pop();
        }
        lock_guard<mutex> l(print_mutex);
        printf("%p %d\n", this_thread::get_id(), data);
        fflush(stdout);
    }
}

int main(int argc, const char * argv[]) {
    thread a(worker);
    thread b(worker);
    int i = 0;
    while (true) {
        // キューにデータを追加する
        {
            lock_guard<mutex> l(queue_mutex);
            v_queue.push(i++);
        }
        // ready_cond変数でwaitしているスレッドのどれか一つのロックを解除する。
        ready_cond.notify_one();
        // 1sec待つ
        usleep(1000000);
    }
    return 0;
}

実行結果

0x100281000 0
0x100304000 1
0x100281000 2
0x100304000 3
0x100281000 4
0x100304000 5
0x100281000 6
0x100304000 7
0x100281000 8
0x100304000 9

1秒毎に結果が表示されている。
今回はたまたま、2つのスレッドが交互にロック解除されているが、
どのスレッドがロックを取得するかに、決まりはない(はず)。

ここでは2つのスレッドを停止させる処理を作っていないが、作る場合は、
notify_one()のほかにnotify_all()という関数で、ロック状態にあるスレッドの全てのwait()を返すことができるので、これを使う。

<参考文献>
C言語で実装しなければならない場合はこちら。
Programming with POSIX Threads / David R. Buternhof / Addison Wesley

Programming with POSIX Threads (Addison-Wesley Professional Computing Series) (English Edition)

Programming with POSIX Threads (Addison-Wesley Professional Computing Series) (English Edition)

C++11を使った並列処理。
最近、C++14/17に対応した改訂版が出たようです。

C++ Concurrency IN ACTION / Anthony Williams / MANNING

C++ Concurrency in Action

C++ Concurrency in Action