boost thread

lambdaに寄り道したが,threadのほう.condition variableとmutexを使って共有bufferを作ってみる.

#include <iostream>
#include <string>
#include <boost/thread.hpp>
#include <cstdlib>
using namespace std;

class buffer {
    list<int> queue;
    boost::condition_variable cond;
    boost::mutex mut;
public:
    void push(int item) {
        {
             boost::lock_guard<boost::mutex> lock(mut);
             queue.push_back(item);
        }
        cond.notify_one();
    }

    int pop() throw(out_of_range) {
        boost::unique_lock<boost::mutex> lock(mut);
        while (queue.empty())
            cond.wait(lock);
        int tmp = queue.front();
        queue.pop_front();
        return tmp;
     }
};

stlのlistをキューとして使っている.まあなにで書いてもあんまり変わらない,ごく普通のコードなんだけど,ちょっと面白いのがlockのかけかた.mutexにもlockという関数があるんだけど,これを直接使わずに,lock クラスのオブジェクトを作る形になっている.こうすると,スコープから抜けるときに自動的にlockクラスのオブジェクトが消去され,そのときにmutexが解放される,ということ.lock/unlockの対応をexceptionとかも含めてちゃんと考えるのは本当に大変なので,これはほんと助かる.

lock にはいろいろな種類があってよく把握できていない.一番単純なlockがlock_guardらしい.pushのほうではlock_guard をpopのほうではunique_lockを使っているのは,condition variableのwaitに渡すのにlock_guardでは受け付けてくれないから.

呼び出す方はこんな感じ.

void producer(buffer * b){
    for (int i = 0; i < 10; i++) {
        sleep(1);
        b->push(i);
    }
}

void consumer(buffer * b, string name) {
    for (int i = 0; i < 10; i++) 
        cout << name << ": " << b->pop() << endl;
}

int main()
{
    buffer b;
    boost:: thread t1(producer, &b);
    boost:: thread t2(consumer, &b, "c0");

    t1.join();
    t2.join();
    return 0;
}

buffer bを参照渡しで渡したかったんだけど,threadのコンストラクタに渡す時点で実体渡しになってしまってできなかった.なんか方法あるんだろうか.