相互排他ロック (mutex ロック) は、スレッドの実行を直列化したいときに使用します。相互排他ロックでスレッド間の同期をとるときは、通常はコードの危険領域が複数のスレッドによって同時に実行されないようにするという方法が用いられます。単一のスレッドのコードを保護する目的で相互排他ロックを使用することもできます。
デフォルトの mutex 属性を変更するには、属性オブジェクトを宣言して初期化します。多くの場合、アプリケーションの先頭部分の一箇所で設定しますので、mutex 属性は、すばやく見つけて簡単に変更できます。表 4-1 に、この節で説明する mutex 属性操作関数を示します。
表 4-1 mutex 属性ルーチン
操作 |
参照先 |
---|---|
mutex 属性オブジェクトの初期化 | |
mutex 属性オブジェクトの削除 | |
mutex の適用範囲設定 | |
mutex のスコープの値の取得 | |
mutex の型属性の設定 | |
mutex の型属性の取得 | |
mutex 属性のプロトコルの設定 | |
mutex 属性のプロトコルの取得 | |
mutex 属性の優先順位上限の設定 | |
mutex 属性の優先順位上限の取得 | |
mutex の優先順位上限の設定 | |
mutex の優先順位上限の取得 | |
mutex の堅牢度属性の設定 | |
mutex の堅牢度属性の取得 |
mutex のスコープ定義について、Solaris のスレッドと POSIX のスレッドとの相違点を表 4-2 に示します。
表 4-2 mutex の適用範囲の比較
Solaris |
POSIX |
定義 |
---|---|---|
USYNC_PROCESS |
PTHREAD_PROCESS_SHARED |
このプロセスと他のプロセスのスレッドの間で同期をとるために使用する |
USYNC_PROCESS_ROBUST |
POSIX に相当する定義なし |
異なるプロセスのスレッド間で安定的に同期をとるために使用する |
USYNC_THREAD |
PTHREAD_PROCESS_PRIVATE |
このプロセスのスレッドの間でだけ同期をとるために使用する |
pthread_mutexattr_init(3THR) は、このオブジェクトに関連付けられた属性をデフォルト値に初期化します。各属性オブジェクトのための記憶領域は、実行時にスレッドによって割り当てられます。
この関数が呼び出されたときの pshared 属性のデフォルト値は PTHREAD_PROCESS_PRIVATE で、初期化された mutex を 1 つのプロセスの中だけで使用できるという意味です。
プロトタイプ: int pthread_mutexattr_init(pthread_mutexattr_t *mattr); #include <pthread.h> pthread_mutexattr_t mattr; int ret; /* 属性をデフォルト値に初期化する */ ret = pthread_mutexattr_init(&mattr); |
mattr は不透明な型で、システムによって割り当てられた属性オブジェクトを含んでいます。mattr のスコープとして取り得る値は、PTHREAD_PROCESS_PRIVATE (デフォルト) と PTHREAD_PROCESS_SHARED です。
mutex 属性オブジェクトを再使用するには、pthread_mutexattr_destroy(3T) への呼び出しによって事前に削除しなければなりません。pthread_mutexattr_init() を呼び出すと、不透明なオブジェクトが割り当てられます。そのオブジェクトが削除されないと、結果的にメモリーリークを引き起こします。
正常終了時は 0 です。それ以外の戻り値は、エラーが発生したことを示します。以下のいずれかの条件が検出されると、この関数は失敗し、次の値を返します。
pthread_mutexattr_destroy(3THR) は、pthread_mutexattr_init() によって生成された属性オブジェクトの管理に使用されていた記憶領域の割り当てを解除します。
プロトタイプ: int pthread_mutexattr_destroy(pthread_mutexattr_t *mattr) #include <pthread.h> pthread_mutexattr_t mattr; int ret; /* 属性を削除する */ ret = pthread_mutexattr_destroy(&mattr); |
正常終了時は 0 です。それ以外の戻り値は、エラーが発生したことを示します。以下の条件が検出されると、この関数は失敗し、対応する値を返します。
pthread_mutexattr_setpshared(3THR) は、mutex 変数の適用範囲を設定します。
mutex 変数の値は、プロセス専用 (プロセス内) とシステム共通 (プロセス間) のどちらかです。pshared 属性を PTHREAD_PROCESS_SHARED 状態に設定して mutex を生成し、その mutex が共有メモリー内に存在する場合、その mutex は複数のプロセスのスレッドの間で共有できます。これは Solaris スレッドにおいて mutex_init() で USYNC_PROCESS フラグを使用するのに相当します。
プロトタイプ: int pthread_mutexattr_setpshared(pthread_mutexattr_t *mattr, int pshared); #include <pthread.h> pthread_mutexattr_t mattr; int ret; ret = pthread_mutexattr_init(&mattr); /* * デフォルト値にリセットする: private */ ret = pthread_mutexattr_setpshared(&mattr, PTHREAD_PROCESS_PRIVATE); |
mutex の pshared 属性を PTHREAD_PROCESS_PRIVATE に設定した場合、その mutex を操作できるのは同じプロセスで生成されたスレッドだけです。
正常終了時は 0 です。それ以外の戻り値は、エラーが発生したことを示します。以下の条件が検出されると、この関数は失敗し、対応する値を返します。
pthread_mutexattr_getpshared(3THR) は、pthread_mutexattr_setpshared() によって定義された、mutex 変数の適用範囲を返します。
プロトタイプ: int pthread_mutexattr_getpshared(pthread_mutexattr_t *mattr, int *pshared); #include <pthread.h> pthread_mutexattr_t mattr; int pshared, ret; /* mutex の pshared を取得する */ ret = pthread_mutexattr_getpshared(&mattr, &pshared); |
属性オブジェクト mattr の pshared の現在値を取得します。これは PTHREAD_PROCESS_SHARED と PTHREAD_PROCESS_PRIVATE のどちらかです。
正常終了時は 0 です。それ以外の戻り値は、エラーが発生したことを示します。以下の条件が検出されると、この関数は失敗し、対応する値を返します。
#include <pthread.h> int pthread_mutexattr_settype(pthread_mutexattr_t *attr , int type); |
pthread_mutexattr_settype(3THR) は、 mutex の 型 (type) 属性を設定します。型 属性のデフォルト値は PTHREAD_MUTEX_DEFAULT です。
型 (type) 引数は mutex の型を指定します。有効な mutex 型を以下に示します。
PTHREAD_MUTEX_NORMAL
この型の mutex はデッドロックを検出しません。スレッドが、この mutex をロック解除しないでもう一度ロックしようとすると、スレッドはデッドロックします。別のスレッドによってロックされた mutex をロック解除しようとした場合、引き起こされる動作は未定義です。また、ロック解除された mutex をロック解除しようとした場合、引き起こされる動作は不定です。
PTHREAD_MUTEX_ERRORCHECK
この型の mutex はエラーチェックを行います。スレッドがこの mutex をロック解除しないでもう一度ロックしようとすると、エラーを返します。別のスレッドがロックした mutex をロック解除しようとすると、エラーを返します。また、ロック解除された mutex をロック解除しようとするとエラーを返します。
PTHREAD_MUTEX_RECURSIVE
スレッドがこの mutex をロック解除しないでもう一度ロックしようとすると、正常にロックできます。PTHREAD_MUTEX_NORMAL 型の mutex ではロックを繰り返すとデッドロックが発生しますが、この型の mutex では発生しません。複数回ロックされた mutex を別のスレッドが獲得するときには、その前に同じ回数ロック解除する必要があります。あるスレッドがロックした mutex を別のスレッドがロック解除しようとすると、エラーが返されます。ロック解除されている mutex をスレッドがロック解除しようとすると、エラーが返されます。mutex の型は、プロセス共有属性が PTHREAD_PROCESS_PRIVATE の mutex に対してだけサポートされます。
PTHREAD_MUTEX_DEFAULT
このタイプの mutex を繰り返しロックしようとした場合、引き起こされる動作は未定義です。この型の mutex を、ロックしていないスレッドがロック解除しようとした場合、引き起こされる動作は未定義です。この型の、ロックされていない mutex をロック解除しようとした場合、引き起こされる動作は未定義です。この型の mutex は、他の mutex 型に割り当てることができます。Solaris スレッドでは、PTHREAD_PROCESS_DEFAULT は PTHREAD_PROCESS_NORMAL に割り当てられます。
pthread_mutexattr_settype 関数は、正常に終了すると 0 を返します。それ以外の場合は、エラーを示す値を返します。
EINVAL
type の値が無効です。
EINVAL
attr で指定された値が無効です。
#include <pthread.h> int pthread_mutexattr_gettype(pthread_mutexattr_t *attr , int *type); |
pthread_mutexattr_gettype(3THR) は、pthread_mutexattr_settype() によって設定された、 mutex の 型 (type) 属性を取得します。型属性のデフォルト値は PTHREAD_MUTEX_DEFAULT です。
型 (type) 引数は mutex の型を指定します。有効な mutex 型を以下に示します。
PTHREAD_MUTEX_NORMAL
PTHREAD_MUTEX_ERRORCHECK
PTHREAD_MUTEX_RECURSIVE
PTHREAD_MUTEX_DEFAULT
各型の説明については、「pthread_mutexattr_settype(3THR)」を参照してください。
pthread_mutexattr_setprotocol(3T) は、mutex 属性オブジェクトのプロトコル属性を設定します。
#include <pthread.h> int pthread_mutexattr_setprotocol(pthread_mutexattr_t *attr, int protocol); |
attr は、先の pthread_mutexattr_init() の呼び出しによって作成された mutex 属性オブジェクトを指します。
protocol には、mutex 属性オブジェクトに適用されるプロトコルを指定します。
pthread.h に定義可能な protocol の値は、PTHREAD_PRIO_NONE、PTHREAD_PRIO_INHERIT、または PTHREAD_PRIO_PROTECT です。
PTHREAD_PRIO_NONE
PTHREAD_PRIO_INHERIT
スレッド (thrd1 など) が所有する 1 つまたは複数の mutex が、より優先順位の高いスレッドによってブロックされている場合、これらの mutex が PTHREAD_PRIO_INHERIT で初期化されていると、このプロトコル値はスレッド (thrd1) の優先順位とスケジューリングに影響します。thrd1 は、より高い優先順位または thrd1 が所有する mutex を待っているスレッドの最高優先順位で実行されます。
thrd1 が別のスレッド thrd3 が所有する mutex をブロックしている場合、同様の優先順位継承効果が thrd3 に対して再帰的に伝播されます。
PTHREAD_PRIO_INHERIT を使用して、優先順位が逆転しないようにしてください。優先順位の低いスレッドが、そのスレッドより優先順位の高いスレッドが必要としているロックを保持していると、優先順位が逆転します。優先順位の高いスレッドは、優先順位の低いスレッドがロックを解除するまで実行を続行できないため、各スレッドは本来の優先順位が逆転しているかのように扱われます。
シンボル _POSIX_THREAD_PRIO_INHERIT が定義されている場合、プロトコル属性値 PTHREAD_PRIO_INHERIT で初期化された mutex では、その mutex の所有者が終了すると Solaris オペレーティング環境で次の動作が発生します。
所有者終了時の動作は、pthread_mutexattr_setrobust_np() の robustness 引数の値によって異なります。
mutex のロックが解除されます。
次の所有者がその mutex を獲得し、エラーコード EOWNERDEAD が返されます。
mutex の次の所有者は、mutex によって保護されている状態を整合させるよう試行する必要があります。これは、前の所有者が終了したときに状態が不整合のままになっている可能性があるためです。所有者が状態を整合させることに成功すると、その mutex に対して pthread_mutex_init() を呼び出して、mutex をロック解除します。
pthread_mutex_init() が前の初期化で呼び出されたが、まだ mutex を削除していない場合、mutex は初期化し直されません。
所有者が状態を整合させることができない場合は、pthread_mutex_init() は呼び出さず、mutex をロック解除します。この場合には、すべての待機者が呼び起こされ、それ以降の pthread_mutex_lock() へのすべての呼び出しは mutex の獲得に失敗し、エラーコード ENOTRECOVERABLE が返されます。この時点で、pthread_mutex_destroy() を呼び出して mutex を削除し、pthread_mutex_init() を呼び出して初期化し直すことによって、mutex の状態を整合させることができます。
EOWNERDEAD を持つロックを獲得したスレッドが終了すると、次の所有者がエラーコード EOWNERDEAD を持つロックを獲得します。
PTHREAD_PRIO_PROTECT
あるスレッドが、PTHREAD_PRIO_PROTECT で初期化された 1 つまたは複数の mutex を所有する場合に、このプロトコル値は、スレッド (thrd2 など) の優先順位とスケジューリングに影響します。thrd2 は、より高い優先順位または自分が所有しているすべての mutex の中で最も高い優先順位で実行します。thrd2 が所有するいずれかの mutex でブロックされているより優先度の高いスレッドは、thrd2 のスケジューリングには影響を与えません。
スレッドが PTHREAD_PRIO_INHERIT または PTHREAD_PRIO_PROTECT で初期化された mutex を所有しており、sched_setparam() の呼び出しなどによってそのスレッドの元の優先順位が変更されている場合は、スケジューラは新しい優先順位のスケジューリングキューの末尾にそのスレッドを移動しません。同様に、PTHREAD_PRIO_INHERIT または PTHREAD_PRIO_PROTECT で初期化された mutex をスレッドがロック解除して、そのスレッドの元の優先順位が変更されている場合は、スケジューラは新しい優先順位のスケジューリングキューの末尾にそのスレッドを移動しません。
PTHREAD_PRIO_INHERIT で初期化された mutex と PTHREAD_PRIO_PROTECT で初期化された mutex を複数同時に所有しているスレッドは、これらのプロトコルのいずれかで獲得された最高の優先順位で実行します。
pthread_mutexattr_setprotocol() は、正常終了すると 0 を返します。それ以外の戻り値は、エラーが発生したことを示しています。
次のどちらかの条件が検出されると、pthread_mutexattr_setprotocol() は失敗し、対応する値を返します。
_POSIX_THREAD_PRIO_INHERIT と_POSIX_THREAD_PRIO_PROTECT のどちらのオプションも定義されておらず、この実装はこの関数をサポートしていません。
protocol で指定された値はサポートされていない値です。
次のどちらかの条件が検出されると、pthread_mutexattr_setprotocol() は失敗し、対応する値を返します。
pthread_mutexattr_getprotocol(3T) は、mutex 属性オブジェクトのプロトコル属性を取得します。
#include <pthread.h> int pthread_mutexattr_getprotocol(const pthread_mutexattr_t *attr, int *protocol); |
attr は、先の pthread_mutexattr_init() の呼び出しによって作成された mutex 属性オブジェクトを指します。
protocol には、プロトコル属性が入ります。値は、PTHREAD_PRIO_NONE、PTHREAD_PRIO_INHERIT、または PTHREAD_PRIO_PROTECT です。
pthread_mutexattr_getprotocol() は、正常終了すると 0 を返します。それ以外の戻り値は、エラーが発生したことを示しています。
次の条件が検出されると、pthread_mutexattr_getprotocol() は失敗し、対応する値を返します。
_POSIX_THREAD_PRIO_INHERIT と _POSIX_THREAD_PRIO_PROTECT のどちらのオプションも定義されておらず、この実装はこの関数をサポートしていません。
次のどちらかの条件が検出されると、pthread_mutexattr_getprotocol() は失敗し、条件に対応する値を返します。
pthread_mutexattr_setprioceiling(3T) は、mutex 属性オブジェクトの優先順位上限属性を設定します。
#include <pthread.h> int pthread_mutexattr_setprioceiling(pthread_mutexattr_t *attr, int prioceiling, int *oldceiling); |
attr は、先の pthread_mutexattr_init() の呼び出しによって作成された mutex 属性オブジェクトを指します。
attr mutex 属性オブジェクトに優先順位上限属性が含まれるのは、シンボル _POSIX_THREAD_PRIO_PROTECT が定義されている場合だけです。
prioceiling には、初期化された mutex の優先順位上限を指定します。優先順位上限は、mutex によって保護されている重要領域が実行される最小の優先レベルを定義します。prioceiling は、SCHED_FIFO によって定義される優先順位の最大範囲内にあります。優先順位が逆転しないように、特定の mutex をロックするすべてのスレッドの中で最も高い優先順位と同じかまたはそれを上回る優先順位を prioceiling として設定します。
oldceiling には古い優先順位上限の値が入ります。
pthread_mutexattr_setprioceiling() は、正常終了すると 0 を返します。それ以外の戻り値は、エラーが発生したことを示しています。
次のいずれかの条件が検出されると、pthread_mutexattr_setprioceiling() は失敗し、対応する値を返します。
次のどちらかの条件が検出されると、pthread_mutexattr_setprioceiling() は失敗し、対応する値を返します。
pthread_mutexattr_getprioceiling(3T) は、mutex 属性オブジェクトの優先順位上限属性を取得します。
#include <pthread.h> int pthread_mutexattr_getprioceiling(const pthread_mutexattr_t *attr, int *prioceiling); |
attr は、先の pthread_mutexattr_init() の呼び出しによって作成された属性オブジェクトを指します。
attr mutex 属性オブジェクトに優先順位上限属性が含まれるのは、シンボル _POSIX_THREAD_PRIO_PROTECT が定義されている場合だけです。
pthread_mutexattr_getprioceiling() は、初期化された mutex の優先順位上限、mutex を prioceiling で返します。この上限は、mutex によって保護されている重要領域が実行される最小の優先レベルを定義します。prioceiling は、SCHED_FIFO によって定義される優先順位の最大範囲内にあります。優先順位が逆転しないように、特定の mutex をロックするすべてのスレッドの中で最も高い優先順位と同じかまたはそれを上回る優先順位を prioceiling として設定します。
pthread_mutexattr_getprioceiling() は、正常終了すると 0 を返します。それ以外の戻り値は、エラーが発生したことを示しています。
次の条件が検出されると、pthread_mutexattr_getprioceiling() は失敗し、対応する値を返します。
次のどちらかの条件が検出されると、pthread_mutexattr_getprioceiling() は失敗し、対応する値を返します。
pthread_mutex_setprioceiling(3T) は、mutex の優先順位上限を設定します。
#include <pthread.h> int pthread_mutex_setprioceiling(pthread_mutexatt_t *mutex, int prioceiling, int *old_ceiling); |
pthread_mutex_setprioceiling() は mutex の優先順位上限、つまり prioceiling を変更します。pthread_mutex_setprioceiling() は、mutex のロックが解除されている場合 mutex をロックするか、または mutex を正常にロックできるようになるまでブロックして、mutex の優先順位上限を変更し、mutex を開放します。mutex をロックするプロセスでは、優先順位保護プロトコルを守る必要はありません。
mutex 属性オブジェクト、つまり mutex に優先順位上限が含まれるのは、シンボル _POSIX_THREAD_PRIO_PROTECT が定義されている場合だけです。
pthread_mutex_setprioceiling() が正常に終了すると、優先順位上限の以前の値が old_ceiling で返されます。pthread_mutex_setprioceiling() が失敗すると、mutex の優先順位上限は元のままになります。
pthread_mutex_setprioceiling() は、正常終了すると 0 を返します。それ以外の戻り値は、エラーが発生したことを示しています。
次の条件が検出されると、pthread_mutexatt_setprioceiling() は失敗し、それに対応する値を返します。
次のいずれかの条件が検出されると、pthread_mutex_setprioceiling() は失敗し、対応する値を返します。
prioceiling で要求された優先順位が範囲外です。
mutex で指定された値は現在の既存の mutex を参照していません。
この実装は mutex の優先順位上限プロトコルをサポートしていません。
呼び出し元はこの操作を行うための権限を持っていません。
pthread_mutex_getprioceiling(3T) は、mutex の優先順位上限を取得します。
#include <pthread.h> int pthread_mutex_getprioceiling(const pthread_mutexatt_t *mutex, int *prioceiling); |
pthread_mutex_getprioceiling() は、mutex の優先順位上限、つまり prioceiling を返します。
pthread_mutex_getprioceiling() は、正常終了すると 0 を返します。それ以外の戻り値は、エラーが発生したことを示しています。
次の条件が検出されると、pthread_mutexatt_getprioceiling() は失敗し、対応する値を返します。
次のいずれかの条件が検出されると、pthread_mutex_getprioceiling() は失敗し、対応する値を返します。
mutex で指定された値は現在の既存の mutex を参照していません。
この実装は mutex の優先順位上限プロトコルをサポートしていません。
呼び出し元はこの操作を行うための権限を持っていません。
pthread_mutexattr_setrobust_np(3T) は、mutex 属性オブジェクトの堅牢度属性を設定します。
#include <pthread.h> int pthread_mutexattr_setrobust_np(pthread_mutexatt_t *attr, int *robustness); |
pthread_mutexattr_setrobust_np() が適用されるのは、シンボル _POSIX_THREAD_PRIO_INHERIT が定義されている場合だけです。
attr は、先の pthread_mutexattr_init() の呼び出しによって作成された mutex 属性オブジェクトを指します。
robustness は、mutex の所有者が終了した場合の動作を定義します。pthread.h に定義可能な robustness の値は、PTHREAD_MUTEX_ROBUST_NP または PTHREAD_MUTEX_STALLED_NP です。デフォルト値は、PTHREAD_MUTEX_STALLED_NP です。
PTHREAD_MUTEX_ROBUST_NP
mutex の所有者が終了すると、それ以降の pthread_mutex_lock() へのすべての呼び出しは、指定しない方法で進行過程からブロックされます。
PTHREAD_MUTEX_STALLED_NP
mutex の所有者が終了すると、mutex はロック解除されます。この mutex の次の所有者が獲得し、エラーコード EOWNERDEAD が返されます。
作成するアプリケーションは、このタイプの mutex について、pthread_mutex_lock() から出力される戻りコードをチェックする必要があります。
この mutex の新しい所有者は、mutex によって保護されている状態を整合させる必要があります。これは、前の所有者が終了したときに状態が不整合のままになっている可能性があるためです。
新しい所有者が状態を整合できる場合は、その mutex に対して pthread_mutex_consistent_np() を呼び出して、mutex をロック解除します。
新しい所有者が状態を整合できない場合は、その mutex に対して pthread_mutex_consistent_np() を呼び出さずに、mutex をロック解除してください。
すべての待機者が呼び起こされ、それ以降の pthread_mutex_lock() へのすべての呼び出しは mutex の獲得に失敗し、エラーコード ENOTRECOVERABLE を返します。この時点で、pthread_mutex_destroy() を呼び出して mutex を削除し、pthread_mutex_int() を呼び出して初期化し直すことによって、mutex の状態を整合させることができます。
EOWNERDEAD を持つロックを獲得したスレッドが終了すると、次の所有者がリターンコード EOWNERDEAD を持つロックを獲得します。
pthread_mutexattr_setrobust_np() は、正常終了すると 0 を返します。それ以外の戻り値は、エラーが発生したことを示しています。
次の条件のいずれかが検出されると、pthread_mutexattr_setrobust_np() は失敗し、対応する値を返します。
オプション _POSIX_THREAD_PRIO__INHERIT が定義されていないか、あるいはこの実装が pthread_mutexattr_setrobust_np() 関数をサポートしていません。
robustness で指定された値はサポートされていません。
次の条件が検出されると、pthread_mutexattr_setrobust_np() は失敗します。
pthread_mutexattr_getrobust_np(3T) は、mutex 属性オブジェクトの堅牢度属性を取得します。
#include <pthread.h> int pthread_mutexattr_getrobust_np(pthread_mutexatt_t *attr, int *robustness); |
pthread_mutexattr_getrobust_np() が適用されるのは、シンボル_POSIX_THREAD_PRIO_INHERIT が定義されている場合だけです。
attr は、先の pthread_mutexattr_init() の呼び出しによって作成された mutex 属性オブジェクトを指します。
robustness は、mutex 属性オブジェクトの堅牢度属性の値です。
pthread_mutexattr_getrobust_np() は、正常終了すると 0 を返します。それ以外の戻り値は、エラーが発生したことを示しています。
次の条件のいずれかが検出されると、pthread_mutexattr_getrobust_np() は失敗し、対応する値を返します。
オプション _POSIX_THREAD_PRIO__INHERIT が定義されていないか、あるいはこの実装が pthread_mutexattr_getrobust_np() 関数をサポートしていません。
robustness で指定された値はサポートされていません。
次の条件が検出されると、pthread_mutexattr_getrobust_np() は失敗します。