読者です 読者をやめる 読者になる 読者になる

Pebble's Diary

プログラマーの作業メモ

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

C++11
#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

Programming with POSIX Threads

C++11を使った並列処理。
C++ Concurrency IN ACTION / Anthony Williams / MANNING

C++ Concurrency in Action: Practical Multithreading

C++ Concurrency in Action: Practical Multithreading