So-net無料ブログ作成
  • ブログをはじめる
  • ログイン

Mac用USBデバイス-60 スレッド間の排他制御 [Mac用USBデバイス工作]

昨日一昨日でMac OS Xのリアルタイムスレッドのことを調べた。今回の問題の特性と現状のハードウェアのパフォーマンスを考えてリアルタイムスレッド導入の必要性は低いと判断した。とりあえずその線で継続する。今日はマルチスレッドプログラミングにはつきものの排他制御のこと。

スレッド間の排他制御

ひとつのデータを二つのスレッドからアクセスするとき、問題がおきる。今回のキューのような場合、キューの内部にはどこまでデータが詰まっているかをあらわす変数を持っているはずである。

例えばキューへの書き込みのとき、その変数を調整してから実際にデータを書き込むするとする。変数を調整したあとすぐに別のスレッドから読み込みが発生したとすると、新しいデータがあるように見える(変数が調整されている)のにデータはまだ書き変わっていないのをしらずに読み込んでしまうことになる。

場合によっては両方のスレッドから同時に変数調整をするようなタイミングも発生するかもしれない。そのときは変数そのものが矛盾した値になって破壊的な状況に陥る(クラッシュする)ということも考えられる。

それをさけるためには、変数調整とデータの変更を、どちらか一方のスレッドからしかできないようにすればいい。

古いunixでの排他制御

古代のunixにも排他制御の機構は存在した。セマフォ(semaphore)という。主にプロセス間通信のひとつである共有メモリの排他制御に使った。これは本来独立しているはずのメモリを特定のアドレス領域に限って複数のプロセスで共有できるようにしたもので、ほかのプロセス間通信(パイプやシグナルなど)に比べて低レベルでプログラマが排他制御する必要があった。セマフォはそのために使うことが多かったが、共有メモリにしか使えない訳ではない。

unixのセマフォは、セマフォ値というのをOSが管理していて、複数のプロセスから
  1. 値を読む
  2. (ある条件を満足したとき)値にある数を足す
  3. (ある条件を満足したとき)値から引く
  4. 値が0になるまでブロックする
などができる。この値は、ざっくりいくつのプロセスがセマフォにアクセスしようとしているかを表していると考えていい。0になればどのプロセスも使っていないということになってセマフォを操作することができる(実際にはもう少し複雑な操作ができて、例えばセマフォを取得した(値を増やした)プロセスがそのまま死んだ場合にもデッドロックが起こらないように考慮されている)。これを使って排他制御を行った。

昔はこれがよく理解できなかった。排他制御したいのは共有メモリなのにセマフォしか制御できないのはなぜか、などと勘違いしていた。

これは、例えば共有メモリを排他制御したいときにその機能を持ったセマフォと組で使う、ということをしないといけない。つまりセマフォを作っておきながらそれを無視して共有メモリをアクセスしたら排他制御は不可能になる。

他の排他制御機構も基本的な使い方は同じである。ただし、Mac OS Xではプロセス以外にスレッド間での排他制御をする必要がある。

Mac OS Xのスレッド間の排他制御

古い話はそのくらいにして今のmac OS Xには排他制御を実現する手段はいくつかある。スレッド間の排他制御にはCocoa/Objective-CのレベルではNSLockというクラスがある。これはいわゆるミューテックスロック(mutually exclusive lock相互排他ロック)といって一番簡単なもの。

NSLockは「ロックをかける」「ロックを解除する」というふたつのことができる。
    NSLock  *theLock;
    [theLock lock];
    //  変数調整とデータ操作
    [theLonk unlock];
lockメソッドはインスタンスのロックをかけようとする。もしこのインスタンスが他のスレッド上でlockを呼ばれていたら、このメソッドはブロックする。そして使っていた他のスレッドでunlockが呼ばれると今度はこのスレッドがロックをかけてメソッドを抜けてくる。unlockを呼ぶまで他のスレッドのlockメソッドはブロックされる。

こうすれば二つのスレッドから同時に変数調整されるということはなくなる。簡単。

そのほかにブロックされないでロックがかけられたか失敗したかを返すtryLockというメソッドなどもある。tryLockの場合、スレッドはブロックされないのでロックが得られるまで他のことができる。

これもかんたん。NSThreadとNSLockでとりあえずのマルチスレッド環境を構築することができる。

ちなみに、NSLockは古いunixのセマフォのようにプロセス間では使えない。そのためにはNSDistributedLockというクラスを使う必要がある。NSDistributedLockのほうはプロセス間だけでなくネットワークワイドにも使える。

nice!(0)  コメント(0)  トラックバック(0) 

nice! 0

コメント 0

コメントを書く

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

トラックバック 0