マルチスレッドのプログラミング

読み取り / 書き込みロックの使用

読み取り / 書き込みロックの属性を設定したあとに、読み取り / 書き込みロックそのものを初期化します。次の関数を使って、読み取り / 書き込みロックを初期化または削除したり、ロックまたはロック解除したり、ロックを試みたりできます。ここで説明した読み取り / 書き込みロック属性を操作する関数を、次の表に示します。

表 4-9 読み取り / 書き込みロック属性のルーチン

操作 

参照先 

読み取り/書き込みロックの初期化 

「pthread_rwlock_init(3T)」

読み取り/書き込みロックの読み取りロック 

「pthread_rwlock_rdlock(3T)」

非ブロック読み取り/書き込みロックの読み取りロック 

「pthread_rwlock_tryrdlock(3T)」

読み取り/書き込みロックの書き込みロック 

「pthread_rwlock_wrlock(3T)」

非ブロック読み取り/書き込みロックの書き込みロック 

「pthread_rwlock_trywrlock(3T)」

読み取り/書き込みロックの解除 

「pthread_rwlock_unlock(3T)」

読み取り/書き込みロックの削除 

「pthread_rwlock_destroy(3T)」

読み取り / 書き込みロックの初期化

pthread_rwlock_init(3T)


#include <pthread.h>

int pthread_rwlock_init(pthread_rwlock_t *rwlock, const pthread_rwlockattr_t *attr);

pthread_rwlock_t  rwlock = PTHREAD_RWLOCK_INITIALIZER;

pthread_rwlock_init(3T) により、attr を参照される属性を使用して、rwlock が参照する読み取り / 書き込みロックを初期化します。attrNULL の場合、デフォルトの読み取り / 書き込みロック属性が使われます。この場合の結果は、デフォルトの読み取り / 書き込みロック属性オブジェクトのアドレスを渡す場合と同じです。いったん初期化したロックは、繰り返して使用するために再び初期化する必要はありません。初期化が成功すると、読み取り / 書き込みロックは初期化され、ロックが解除された状態になります。初期化済みの読み取り / 書き込みロックを指定して、pthread_rwlock_init() を呼び出した場合、その結果は不定です。最初に初期化しないで読み取り / 書き込みロックを使用した場合も、その結果は不定です。Solaris スレッドについては、「rwlock_init(3T)」を参照してください。

デフォルトの読み取り / 書き込みロック属性を使用するのであれば、PTHREAD_RWLOCK_INITIALIZER というマクロを使用して、静的に割り当てられている読み取り / 書き込みロックを初期化できます。この場合の結果は、パラメータ attrNULL を指定して pthread_rwlock_init() を呼び出し、動的に初期化したときと同じです。ただし、エラーチェックが実行されません。

戻り値

正常終了時は 0 です。それ以外の戻り値は、エラーが発生したことを示します。

pthread_rwlock_init() が正常に終了しなかった場合、rwlock は初期化されず、rwlock の内容は未定義です。


EINVAL

attr または rwlock が示す値は無効です。

読み取り / 書き込みロックの読み取りロック

pthread_rwlock_rdlock(3T)


#include <pthread.h>

int  pthread_rwlock_rdlock(pthread_rwlock_t *rwlock );

pthread_rwlock_rdlock(3T) は、rwlock が参照する読み取り / 書き込みロックに読み取りロックを適用します。書き込みがロックを保持せず、読み取り / 書き込みロックでブロックされている書き込みもない場合は、呼び出しスレッドは読み取りロックを獲得します。書き込みがロックを保持せず、ロック待ちの書き込みがある場合は、呼び出しスレッドが読み取りロックを獲得するかどうかは不定です。書き込みが読み取り / 書き込みロックを保持している場合は、呼び出しスレッドは読み取りロックを獲得しません。読み取りロックが獲得されない場合、呼び出しスレッドは読み取りロックを獲得するまでブロックします。つまり、呼び出しスレッドは、pthread_rwlock_rdlock() から戻り値を取得しません。呼び出し時に、呼び出しスレッドが rwlock に書き込みロックを保持する場合、その結果は不定です。

書き込み側がいつまでもロックを獲得できない事態を避けるために、書き込みが読み取りに優先するように実装できます。たとえば、Solaris スレッドの実装では、書き込みが読み取りに優先します。「rw_rdlock(3T) 」 を参照してください。

スレッドは、rwlock に複数の並行的な読み取りロックを保持できます。つまり、pthread_rwlock_rdlock() の呼び出しが n 回成功します。この場合、スレッドは同数の読み取りロック解除を行わなければなりません。つまり、pthread_rwlock_unlock()n 回呼び出さなければなりません。

pthread_rwlock_rdlock() が、初期化されていない読み取り / 書き込みロックに対して呼び出された場合、その結果は不定です。

読み取りのための読み取り / 書き込みロックを待っているスレッドにシグナルが送られた場合、スレッドはシグナルハンドラから戻ると、見かけ上割り込みがなかった場合と同様に、読み取りのための読み取り / 書き込みロック待ちを再開します。

戻り値

正常終了時は 0 です。それ以外の戻り値は、エラーが発生したことを示します。


EINVAL

attr または rwlock が示す値は無効です。

非ブロック読み取り / 書き込みロックの読み取りロック

pthread_rwlock_tryrdlock(3T)


#include <pthread.h>

int pthread_rwlock_tryrdlock(pthread_rwlock_t *rwlock);

pthread_rwlock_tryrdlock(3T) は、pthread_rwlock_rdlock() と同様に読み取りロックを適用します。ただし、いずれかのスレッドが rwlock に書き込みロックを保持しているか、rwlock で書き込みスレッドがブロックされている場合、この関数は失敗します。Solaris スレッドについては、「rw_tryrdlock(3T)」 を参照してください。

戻り値

rwlock が参照する読み取り / 書き込みロックオブジェクトに対する読み取りロックが獲得された場合、戻り値は 0 です。それ以外の戻り値は、エラーが発生したことを示します。


EBUSY

書き込みが読み取り / 書き込みロックを保持しているか、読み取り / 書き込みロックで書き込みスレッドがブロックされているため、読み取りのための読み取り / 書き込みロックを獲得できません。

読み取り / 書き込みロックの書き込みロック

pthread_rwlock_wrlock(3T)


#include <pthread.h>

int  pthread_rwlock_wrlock(pthread_rwlock_t *rwlock );

pthread_rwlock_wrlock(3T) は、rwlock が参照する読み取り / 書き込みロックに書き込みロックを適用します。 ほかのスレッド (読み取り側または書き込み側) が rwlock という読み取り / 書き込みロックを保持していない場合、呼び出しスレッドは書き込みロックを獲得します。これ以外の場合、スレッドは、ロックを獲得するまでブロックされます。つまり、pthread_rwlock_wrlock() の呼び出しから戻りません。呼び出し時に、呼び出しスレッドが読み取り / 書き込みロックを保持している場合 (読み取りロックと書き込みロックのどちらでも) の結果は不定です。

書き込み側がいつまでもロックを獲得できない事態を避けるために、書き込みが読み取りに優先するように実装することが許されています。たとえば、Solaris スレッドの実装では、書き込みが読み取りに優先します。「rw_wrlock(3T) 」を参照してください。

pthread_rwlock_wrlock() が、初期化されていない読み取り / 書き込みロックに対して呼び出された場合、その結果は不定です。

書き込みのための読み取り / 書き込みロックを待っているスレッドにシグナルが送られた場合、スレッドはシグナルハンドラから戻ると、見かけ上割り込みがなかった場合と同様に、書き込みのための読み取り / 書き込みロック待ちを再開します。

戻り値

rwlock が参照する読み取りは / 書き込みロックオブジェクトの書き込みロックが獲得された場合、あり得る戻りの記述が存在しないことを示します。

非ブロック読み取り / 書き込みロックの書き込みロック

pthread_rwlock_trywrlock(3T)


#include <pthread.h>

int pthread_rwlock_trywrlock(pthread_rwlock_t  *rwlock);

pthread_rwlock_trywrlock(3T) は、pthread_rwlock_wrlock() と同様に書き込みロックを適用します。ただし、いずれかのスレッドが現時点で rwlock (読み取り用または書き込み用) を保持している場合、この関数は失敗します。Solaris スレッドについては、「rw_trywrlock(3T)」 を参照してください。

pthread_rwlock_trywrlock() が、初期化されていない読み取り / 書き込みロックに対して呼び出された場合、その結果は不定です。

書き込みのための読み取り / 書き込みロックを待っているスレッドにシグナルが送られた場合、スレッドはシグナルハンドラから戻ると、見かけ上割り込みがなかった場合と同様に、書き込みのための読み取り / 書き込みロック待ちを再開します。

戻り値

rwlock が参照する読み取り / 書き込みロックオブジェクトの書き込みロックを獲得した場合、戻り値は 0 です。それ以外の戻り値は、エラーが発生したことを示します。


EBUSY

読み取りまたは書き込みでロック済みのため、書き込みのための読み取り / 書き込みロックを獲得できません。

読み取り / 書き込みロックの解除

pthread_rwlock_unlock(3T)


#include <pthread.h>

pthread_rwlock_unlock(3T) は、rwlock が参照する読み取り / 書き込みロックオブジェクトに保持されたロックを解放します。呼び出しスレッドが rwlock という読み取り / 書き込みロックを保持していない場合、その結果は不定です。Solaris スレッドについては、「rw_unlock(3T) 」 を参照してください。

pthread_rwlock_unlock を呼び出して読み取り / 書き込みロックオブジェクトから読み取りオブジェクトを解放しても、この読み取り / 書き込みロックオブジェクトに他の読み取りロックが保持されている場合、読み取り / 書き込みロックオブジェクトは読み取りにロックされたままになります。pthread_rwlock_unlock() が、呼び出しスレッドによる最後の読み取りロックを解放すると、呼び出しスレッドはこのオブジェクトの所有者でなくなります。pthread_rwlock_unlock() がこの読み取り / 書き込みロックオブジェクトの最後の読み取りロックを解放すると、読み取り / 書き込みロックオブジェクトはロックが解除され、所有者のない状態になります。

pthread_rwlock_unlock() を呼び出し、読み取り / 書き込みロックオブジェクトから書き込みオブジェクトを解放すると、読み取り / 書き込みロックオブジェクトはロックが解除され、所有者のない状態になります。

pthread_rwlock_unlock() を呼び出した結果として読み取り / 書き込みロックオブジェクトがロック解除されたときに、複数のスレッドが書き込みのための読み取り / 書き込みロックオブジェクトの獲得を待っている場合は、スケジューリング方針を使用して、書き込みのための読み取り / 書き込みロックオブジェクトを獲得するスレッドが決定されます。また、複数のスレッドが読み取りのための読み取り / 書き込みロックオブジェクトの獲得を待っている場合も、スケジューリング方針を使用して、読み取りのための読み取り / 書き込みロックオブジェクトを獲得するスレッドの順番が決定されます。さらに、複数のスレッドが読み取りロックと書き込みロック両方のために rwlock にブロックされている場合は、読み取り側と書き込み側のどちらが先にロックを獲得するのかは規定されていません。

pthread_rwlock_unlock() が、初期化されていない読み取り / 書き込みロックに対して呼び出された場合、その結果は不定です。

戻り値

正常終了時は 0 です。それ以外の戻り値は、エラーが発生したことを示します。

読み取り / 書き込みロックの削除

pthread_rwlock_destroy(3T)


#include <pthread.h>

int pthread_rwlock_destroy(pthread_rwlock_t *rwlock);

pthread_rwlock_t  rwlock = PTHREAD_RWLOCK_INITIALIZER;

pthread_rwlock_destroy(3T) は、rwlock が示す読み取り / 書き込みロックオブジェクトを削除し、このロックで使用されていたリソースを解放します。削除したオブジェクトを、pthread_rwlock_init() の呼び出しによって再び初期化する前に使用した場合、その結果は不定です。実装によっては、pthread_rwlock_destroy() は、rwlock が参照するオブジェクトに不正な値を設定する場合もあります。いずれかのスレッドが rwlock を保持しているときに pthread_rwlock_destroy() を呼び出した場合の結果は不定です。初期化されていない読み取り / 書き込みロックを削除しようとした場合に発生する動作も不定です。また、削除された読み取り / 書き込みロックオブジェクトは、再度 pthread_rwlock_init() で初期化できます。削除した読み取り / 書き込みロックオブジェクトを初期化せずに参照した場合も不定です。Solaris スレッドについては、「rwlock_destroy(3T) 」 を参照してください。

戻り値

正常終了時は 0 です。それ以外の戻り値は、エラーが発生したことを示します。


EINVAL

attr または rwlock が示す値は無効です。