SSブログ

CFRunLoopSourceの使い方その3 [考え中の問題]

先日までで歴史のお話は終わり。これから比較的低レベルでのスレッド操作のための材料を集める。

3  一般的なスレッド間通信

ということで、最近のCPUに積まれている複数のコアを使い倒すにはスレッドのプログラミングが重要である、という話であった。しかしプロセスと違って同じ仮想空間を共有するのでメモリアクセスにはシングルスレッドや複数プロセスのプログラミングとは違った技術が必要になる。さらに十分マルチコアの性能を引き出すためのプログラミングは、問題によっては非常に難しい場合がある。

とりあえずさくっとスレッド間での通信(同期や排他制御と言った情報のやり取りのためのメカニズム)をおさらいしておく。スレッドそのものの生成や属性設定は前やったのでここではわかっていることにする。

昔のunixにはプロセス間通信なら
  • シグナル
  • パイプ
  • セマフォ
  • 共有メモリ
  • RPC(ソケットなどを使った)
などいろいろあるけどスレッドの間を橋渡しする特別なメカニズムはなかった。プロセス間では共有する変数領域が何もしなければ存在しないので専用のメカニズムが必要になるけど、スレッドはもともと仮想メモリを共有するのでロックとそれに結びついた変数領域があれば通信はできてしまう。またプロセス間通信のメカニズムをスレッド間で使って悪い理由はない。ただしその場合、当然効率は余りよくはない。

ここ十数年ぐらいの間にプログラミングでのスレッドの重要性が増してたので、スレッドのプログラミングを簡単にするためにPOSIX標準としてスレッドの生成破棄なんかといっしょにスレッド間通信も標準化された。pthreadと言う。スレッド間通信と言ってもプロセスと違って通信そのもののメカニズムが必要なわけではない。実質的に排他制御の機能を持っているだけである。

さらに、MacOS XではCore Foundationのレベルで使うことのできるいくつかのスレッド間通信のための部品が用意されている。
  • pthreadによる排他制御
  • Atomic Operation(不可分操作)やその他の代替
  • 実行ループソース
などがある。まずMacOS Xだけでなく一般のunixでも使えるものから。

3.1  pthread ロック

pthreadのロックはCではよく使われる排他制御の手段である。さっきも書いたがPOSIXで比較的新しく標準化されたため、システムコールとしての互換性は比較的高い。

例えばフラグを操作するとき
    int     flag;
    pthread_mutex_t    mutex;
    pthread_mutex_init(&mutex,NULL);  // (1)
    ....
    pthread_mutex_lock(&mutex);       // (2)
    if (flag)
        flag = false;
    pthread_mutex_unlock(&mutex);     // (3)
などとやる。この(2)のlockと(3)のunlockに挟まれたコードは、ひとつのスレッドだけでしか実行されないようにすることが可能になる。

ここではflagという変数をチェックしてtrueなら反転する、という操作をしているが、その間に他のスレッドがflag変数アクセスしないようにできるので、チェックしたあとたまたま他のスレッドで値が変更されてしまって、そのあとfalseにしてしまう、などと言うことを避けられる。

ただし、他のスレッドもflag変数を操作するときは同じようにmutexに対する操作で囲まなければならない。ロックは単に「ロックする」という動作そのものをひとつのスレッドだけでできるようにするメカニズムであって、特定の変数(ここではflag変数)を自動的に排他制御するわけではない。つまりlockとunclockに囲まれたところがひとつのスレッドだけで実行されるというわけではない。

例えば別のスレッドに
     flag = true;
というコードがあったとする。

このコードはさっきの(2)と(3)の間に実行される可能性がある。この変数の排他制御をしたいならこっちのスレッドでも
    pthread_mutex_lock(&mutex);    // (4)
    flag = true;
    pthread_mutex_unlock(&mutex); 
としなければならない。このコードだと、もしさっきの(2)と(3)の間に実行されようとしたら、(4)で実行がブロックされる。ロック変数(ここではmutex)はひとつのスレッドでだけロックが可能であるためである。そして(3)が実行されると(4)のブロックが解かれて変数の値が書き換えられる。

これが一番基本的な使い方だけど、pthreadのロックはいろいろなことができる高機能なものになっている。そのため若干オーバーヘッドが大きい、とも言える。

もちろん排他制御というのはなんでもそうだけど、ちゃんと使わないとデッドロック、つまり複数のスレッドがロックを奪い合って何もしなくなるという状態を起こす。ロックを使うと必ずデッドロックするなら、まだデバグもしやすいんだけど、他のスレッドの状態によってデッドロックになったりならなかったりということも起こりえる。

まだあるけど、残りはまた明日にする。寝る。
nice!(0)  コメント(0)  トラックバック(0) 

nice! 0

コメント 0

コメントを書く

お名前:
URL:
コメント:
画像認証:
下の画像に表示されている文字を入力してください。

トラックバック 0

献立02/04献立02/05 ブログトップ

この広告は前回の更新から一定期間経過したブログに表示されています。更新すると自動で解除されます。