マルチスレッド

pthread_cond_*系でスレッド同期をするという話。
演習のときはかなりテンパってたけど、サンプルコード無視して、
manしたほうが早かったという話。

というわけで解説


マルチスレッドにおけるモニタとは、セマフォよりも複雑だけど、欠点を克服したパターンらしい。
まぁ良く知らんけど。

とにかく、UNIXシステムコールで実装する上でポイントとなる点を列挙してみる。

ポイント
  1. モニタ用ロック1つ(pthread_mutex)を使って、モニタメソッドの呼び出しを整列する。
  2. 任意の数のスレッド同期用の状態記録オブジェクト(pthread_cond)を用意し、これを伝書鳩に使う。
  3. 状態の変更を通知するにはpthread_cond_broadcastを用いる。
  4. 状態の変更を待つには、状態をwhileの条件に書き、内部でpthread_cond_waitを使う。
解説

ポイントの番号と対応してる。

  1. モニタ用のロックは1つだけ。これによって、モニタメソッドを複数のスレッドが同時に実行することを防ぐ。(Javaのsynchronize)
  2. 今回は箸が5本あるので、pthread_condも5個用意する。箸には使用の可否と、待ち状態の二つの変数が対応付けられているが、どちらもpthread_cond一つで対処している。相手先のwhileの条件がfalseなら、もう一度スリープに入るから問題ない。
  3. pthread_cond_broadcastによって、pthread_cond_waitの部分でスリープしていたスレッドが動き出す。待っている相手が唯一と保証できるならpthread_cond_signalを使える。通知は状態が変化したのが判明してから、それ以降任意のタイミングで良いと思われる。
  4. pthread_cond_waitにモニタ用ロックを同時に渡すことで、実行したスレッドはスリープに入り、ロックを開放する。これによって他のスレッドがモニタを実行できるようになる。スレッドのウェイクは、pthread_cond_broadcastによって行われる。
サンプルコード(待つ部分、通知する部分のみ)
bool hage=true; //ハゲてる。
pthread_cond_t condition;

monitor_wait()
{
  pthread_mutex_lock(&lock);

  // 生えるのを待つ。
  while(hage==true){
    // lockを渡すことで、スリープしたときはロックが解除される。
    pthread_cond_wait(&condition, &lock);
  }

  // 生えた!
  printf("I got hair!\n");

  pthread_mutex_unlock(&lock);
}

monitor_notify()
{
  pthread_mutex_lock(&lock);
  ...
  //ここで状態が変わる。
  hage=false; // 生えた。
  pthread_cond_broadcast(&condition); // これによりmonitor_waitが起きる。
  ...
  pthread_mutex_unlock(&lock);
}