説明
mutex は、排他制御 (MUTual EXclusion) の仕組みであり、共有データの同時更新からの保護、クリティカルセクション (critical section) やモニタの実装などに使われる。
mutex は二つの状態を取りうる。それは、アンロック状態(どのスレッドにも保有されていない)とロック状態(一つのスレッドに保有されている)である。二つの異なるスレッドが同時に一つの mutex を保有することはない。既に他のスレッドによってロックされた mutex をロックしようとするスレッドは、保有側のスレッドが先にその mutex をアンロックするまで実行を停止させられる。
pthread_mutex_init は
mutex が指す mutex オブジェクトを、
mutexattr で指定された mutex 属性オブジェクトに従って初期化する。
mutexattr が
NULL, ならば、デフォルトの属性がこのかわりに使われる。
LinuxThreads の実装はただ一つの属性
mutex kind だけに対応している。この属性は、「速い」(``fast'')、「再帰的な」(``recursive'')、または「エラー検査を行なう」(``error checking'')のいずれかを指定するものである。 mutex の種別(kind)は、その mutex を既に保有しているスレッドが、それを再びロックできるかどうかを決定する。デフォルトの種別は「速い」である。mutex 属性のより詳しい情報は、
pthread_mutexattr_init(3) を見よ。
pthread_mutex_t 型の変数は、(速い mutex に対する)定数
PTHREAD_MUTEX_INITIALIZER と、(再帰的 mutex に対する)
PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP および、(エラー検査を行なう mutex に対する)
PTHREAD_ERRORCHECK_MUTEX_INITIALIZER_NP で、静的に初期化することもできる。
pthread_mutex_lock は、与えられた mutex をロックする。mutex が現在ロックされていなければ、それはロックされ、呼び出しスレッドによって所有される。この場合
pthread_mutex_lock は直ちに返る。mutex が他のスレッドによって既にロックされていたのならば、
pthread_mutex_lock は mutex がアンロックされるまで呼び出しスレッドの実行を停止させる。
mutex が呼び出し側のスレッドにより既にロックされている場合には、
pthread_mutex_lock の振舞いは、mutex の種別に依存する。mutex の種別が「速い」であれば、呼び出しスレッドは mutex がアンロックされるまで実行を停止する。従って事実上呼び出しスレッドのデッドロックを引き起こす。 mutex の種別が「エラーをチェックする」であれば、
pthread_mutex_lock はエラーコード
EDEADLK とともに直ちに戻る。mutex の種別が「再帰的」ならば、
pthread_mutex_lock は成功し直ちに戻る。この際、呼び出しスレッドが、その mutex をロックした回数を記録する。この mutex がアンロック状態に戻るには、同数の
pthread_mutex_unlock 操作が実行されねばならない。
pthread_mutex_trylock は
pthread_mutex_lock と同様に振舞うが、mutex が既に他のスレッドによって (あるいは、「速い」 mutex の場合、呼び出しスレッドによって) ロックされている場合、呼び出しスレッドをブロックしない。かわりに、
pthread_mutex_trylock はエラーコード
EBUSY で直ちに戻る。
pthread_mutex_unlock は、与えられた mutex をアンロックする。
pthread_mutex_unlock の開始時点で、この mutex は呼び出しスレッドによりロックされ所有されているものと仮定される。
mutex が「速い」種別のものならば、
pthread_mutex_unlock は常にそれをアンロック状態に戻す。それが「再帰的な」種別ならば、
mutex のロック計数(この mutex に対して
pthread_mutex_lock 操作が呼び出しスレッドで実行された回数) を一つ減らし、この計数がゼロになった時に、初めて mutex が実際にアンロックされる。
「エラーを検査する」mutex に対しては、
pthread_mutex_unlock は実行時に実際に、mutex が開始時点でロックされているか、また、それは現在
pthread_mutex_unlock を呼んでいるのと同じスレッドによってロックされたかどうか、を検査する。これらの条件が満たされない場合には、エラーコードが返され、mutex は不変のままにされる。「速い」mutex と「再帰的な」mutex はこのようなチェックを行なわなず、よって、ロックされた mutex を所有者以外のスレッドによってアンロックすることを可能にしている。これは、移植性のない振舞いであり、これに依存するようなことはすべきでない。
pthread_mutex_destroy は、mutex オブジェクトを破壊し、それが保持している可能性のある資源を開放する。mutex は関数の開始時点でアンロックされていなければならない。LinuxThreads の実装では、いかなる資源も mutex オブジェクトに付随していない。故に
pthread_mutex_destroy は実際のところ、mutex がアンロックされているかどうかを検査する以外のことは何もしない。
例
共有される大域変数
x は mutex により次のように保護される:
int x;
pthread_mutex_t mut = PTHREAD_MUTEX_INITIALIZER;
全ての
x へのアクセスとその変更は
pthread_mutex_lock と
pthread_mutex_unlock によって、次のように囲まれていなければならない:
pthread_mutex_lock(&mut);
/* x の操作 */
pthread_mutex_unlock(&mut);
[訳注] glibc-linuxthreads の最新のドキュメントは Texinfo 形式で提供されている。上の記述は glibc-linuxthreads-2.2 以降では正しくない。以下は glibc-linuxthreads-2.3.1 の Texinfo ファイルからの引用である。種別 (kind) が型 (type) に変更されている。
LinuxThreads 実装はただ 1 つの mutex 属性に対応している。それは mutex 型 (mutex type) で、「速い (fast) 」、「再帰的な (recursive) 」、「時刻情報つき (timed) 」、「エラー検査を行なう (error checking) 」のいずれかである。 mutex 型は、あるスレッドが自分自身ですでに保持している mutex をロックできるかどうかを決定する。デフォルトの mutex 型は「時刻情報つき (timed) 」である。
pthread_mutex_t 型の変数は、定数
PTHREAD_MUTEX_INITIALIZER ( 時刻情報つき (timed) mutex 用 ) 、
PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP ( 再帰的な (recursive) mutex 用 ) 、
PTHREAD_ADAPTIVE_MUTEX_INITIALIZER_NP ( 速い (fast) mutex 用 ) 、
PTHREAD_ERRORCHECK_MUTEX_INITIALIZER_NP ( エラー検査を行なう (error checking) mutex 用 ) を用いて静的に初期化することもできる。