ファイヤープロジェクト
ロックとmutex
2007-02-20T23:00+09:00   matsu
スレッドの同期には,pthread_joinによる合流の他に,ロックという方法がある.
mutexはmutual exclusionの略らしい. ということは,mutexは「ミューテクス」とかそんな感じの読みのような気がするが,正しい読みはよくわからない(※). とにかく,pthreadでは,mutexをロックすることによって,スレッド間の同期を行うことができる.
mutex = バイナリセマフォ
ということで,よいと思う. つまり,あるスレッドでロックしたmutexに対し,別のスレッドがロックしようとしたら,最初のスレッドがそのmutexを開放するまで後のスレッドは待たされる.
上図で,破線で囲まれた部分の処理が,同期が保証される領域で,クリティカルセクションという. 具体的にはクリティカルセクションでは,複数のスレッドで参照,更新するデータに対する処理を行う. クリティカルセクションで参照するデータは,別のスレッドによって更新途中になっている不完全なデータを参照したり更新したりしてしまう心配がない. 性能の観点からすると,クリティカルセクションは短い程よい.
※ 私はどういうわけか,「ムテフ」とか「マテフ」と読んでしまうが,これは,まぁ,間違ってるんだろうな.
mutexはまず初期化する必要がある.
int pthread_mutex_init(pthread_mutex_t *mutex,
                       const  pthread_mutex-attr_t *mutexattr);
pthread_mutex_initはmutexattarで指定した属性をもつmutexを作成する. Linuxではmutex属性はmutex kindのみであり,これには以下があり,ロック使用としたmutexがすでにロックされていた場合の挙動が異なる.
fast
対象のmutexが開放されるまで待つ.
recursive
すぐに返る. mutexにはロックされた回数が保持され,同数アンロックされるまでロック解除状態にはならない... 共有ロックで使用できそうな気もするが,ロック状態とロック解除状態は外からどうやって見分けるんだ?
error checking
ロック関数はすぐに返る. 返り値はEDEADLK.
mutexを破壊する関数もある.
int pthread_mutexattr_destroy(pthread_mutexattr_t *attr);
仕様としては,破壊したmutexは使用してはならない. Linuxではこの関数は何もしないらしいが,OSやハードウェアによってはmutexのために何か資源を保持するかもしれないので,いらなくなったら破壊しておくのが行儀のよいコードらしい. 可搬性はないようだが,以下のマクロによって,簡単にmutexを初期化できる.
pthread_mutex_t fastmutex = PTHREAD_MUTEX_INITIALIZER;
pthread_mutex_t recmutex = PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP;
pthread_mutex_t errchkmutex = PTHREAD_ERRORCHECK_MUTEX_INITIALIZER_NP;
それぞれmutex kindがfast,recursive,error checkingであるmutexを作成する.
mutexを作成したら,あとは各スレッドにてロックしたりアンロックしたりする. ロックには
int pthread_mutex_lock(pthread_mutex_t *mutex));
を使用する. 引数に指定したmutexに対し,ロックをかける. 指定したmutexがロックされていた場合の挙動はmutex属性による.
int pthread_mutex_trylock(pthread_mutex_t *mutex);
は,基本的にpthread_mutex_lockと同様だが,mutex種別がfastで,指定したmutexがロック中でもすぐに返る. この際の返り値はEBUSY.
int pthread_mutex_unlock(pthread_mutex_t *mutex);
では,指定したmutexをアンロックする. mutex属性がerror checkingであれば,指定したmutexがロックされていなかったり,呼び出したスレッドがロックしたスレッドでなければエラーになる. 逆に言うと,mutex属性がfastやrecursiveだとロックされたmutexを別のスレッドでアンロックできるようになっているが,可搬性のためには使用すべきでない.
ではサンプルを示す.
matsu(C)
Since 2002
Mail to matsu