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

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

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

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

操作 

参照先 

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

pthread_rwlock_init の構文」

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

pthread_rwlock_rdlock の構文」

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

pthread_rwlock_tryrdlock の構文」

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

pthread_rwlock_wrlock の構文」

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

pthread_rwlock_trywrlock の構文」

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

pthread_rwlock_unlock の構文」

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

pthread_rwlock_destroy の構文」

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

attr が参照する属性を使用して rwlock が参照する読み取り/書き込みロックを初期化するには、pthread_rwlock_init(3C) を使用します。

pthread_rwlock_init の構文

#include <pthread.h>

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

pthread_rwlock_t  rwlock = PTHREAD_RWLOCK_INITIALIZER;

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

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

pthread_rwlock_init の戻り値

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

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


EINVAL

説明:

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

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

pthread_rwlock_rdlock(3C) は、rwlock が参照する読み取り/書き込みロックに読み取りロックを適用します。

pthread_rwlock_rdlock の構文

#include <pthread.h>

int  pthread_rwlock_rdlock(pthread_rwlock_t *rwlock );

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

書き込み側がいつまでもロックを獲得できない事態を避けるために、書き込みが読み取りに優先するように実装することが許されています。Solaris スレッドの実装では、書き込みが読み取りに優先します。

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

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

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

pthread_rwlock_rdlock の戻り値

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


EINVAL

説明:

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

指定した絶対時間までの読み取り/書き込みロックの読み取りロックの獲得

pthread_rwlock_timedrdlock(3C) 関数は、pthread_rwlock_rdlock() 関数と同様に、rwlock が参照する読み取り/書き込みロックに読み取りロックを適用します。

pthread_rwlock_timedrdlock の構文

#include <pthread.h>
#include <time.h>

int  pthread_rwlock_timedrdlock(pthread_rwlock_t *restrict rwlock,
          const struct timespec *restrict abs_timeout);

ほかのスレッドによるロック解除を待たなければロックを獲得できない場合、この待機は、指定されたタイムアウトの期限が切れると終了します。タイムアウトの期限が切れるのは、abs_timeout で指定された絶対時間 (CLOCK_REALTIME クロックで測定される) が経過した場合 (つまり、そのクロックの値が abs_timeout に等しくなるか、超えた場合)、または呼び出し時に abs_timeout で指定された絶対時間がすでに過ぎている場合です。

タイムアウトの解像度は、CLOCK_REALTIME クロックの解像度です。timespec データ型は、<time.h> ヘッダーで定義されています。ロックをただちに獲得できる場合は、この関数がタイムアウトで失敗することはありません。ロックをただちに獲得できた場合は、タイムアウトパラメータの妥当性を検査する必要はありません。

pthread_rwlock_timedrdlock() の呼び出しによって読み取り/書き込みロックでブロックされているスレッドに、シグナルハンドラを実行させるシグナルが送信された場合、このスレッドはシグナルハンドラから復帰すると、中断がなかったかのようにロックの待機を再開します。

呼び出しスレッドは、呼び出し時に rwlock に書き込みロックを保持しているとデッドロックに陥る可能性があります。

pthread_rwlock_reltimedrdlock_np() 関数は、タイムアウトが相対時間間隔として指定される点を除いて、pthread_rwlock_timedrdlock() 関数と同じ動作をします。

pthread_rwlock_timedrdlock の戻り値

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


ETIMEDOUT

説明:

指定されたタイムアウトの期限が切れる前にロックを獲得できませんでした。


EAGAIN

説明:

ロックの読み取りロックの最大数を超えるため、読み取りロックを獲得できません。


EDEADLK

説明:

呼び出しスレッドは、rwlock をすでに保持しています。


EINVAL

説明:

rwlock で指定された値が初期化された読み取り/書き込みロックオブジェクトを表していないか、タイムアウトのナノ秒の値が 0 未満または 10 億以上です。

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

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

pthread_rwlock_tryrdlock の構文

#include <pthread.h>

int pthread_rwlock_tryrdlock(pthread_rwlock_t *rwlock);

pthread_rwlock_tryrdlock の戻り値

pthread_rwlock_tryrdlock() は、rwlock が参照する読み取り/書き込みロックオブジェクトに対する読み取りロックが獲得された場合、0 を返します。ロックが獲得されなかった場合は、エラーを示すエラー番号が返されます。


EBUSY

説明:

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

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

pthread_rwlock_wrlock(3C) は、rwlock が参照する読み取り/書き込みロックに書き込みロックを適用します。

pthread_rwlock_wrlock の構文

#include <pthread.h>

int  pthread_rwlock_wrlock(pthread_rwlock_t *rwlock );

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

書き込み側がいつまでもロックを獲得できない事態を避けるために、書き込みが読み取りに優先するように実装することが許されています。Solaris スレッドの実装では、書き込みが読み取りに優先します。

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

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

pthread_rwlock_wrlock の戻り値

pthread_rwlock_wrlock() は、rwlock が参照する読み取り/書き込みロックオブジェクトに対する書き込みロックが獲得された場合、0 を返します。ロックが獲得されなかった場合は、エラーを示すエラー番号が返されます。

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

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

pthread_rwlock_trywrlock の構文

#include <pthread.h>

int pthread_rwlock_trywrlock(pthread_rwlock_t  *rwlock);

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

pthread_rwlock_trywrlock の戻り値

pthread_rwlock_trywrlock() は、正常に終了して、rwlock が参照する読み取り/書き込みロックに対する書き込みロックが獲得された場合、0 を返します。それ以外の戻り値は、エラーが発生したことを示します。


EBUSY

説明:

読み取りまたは書き込みのための読み取り/書き込みロックがすでにロックされているので、書き込みのための読み取り/書き込みロックを獲得できません。

指定した絶対時間までの読み取り/書き込みロックの書き込みロックの獲得

pthread_rwlock_timedwrlock(3C) 関数は、pthread_rwlock_wrlock () 関数と同様に、rwlock が参照する読み取り/書き込みロックに書き込みロックを適用しますが、指定された絶対時間までしかロックを適用しようとしません。

pthread_rwlock_timedwrlock の構文

#include <pthread.h>
#include <time.h>

int  pthread_rwlock_timedwrlock(pthread_rwlock_t   *restrict rwlock, 
     const struct timespec *restrict abs_timeout);

呼び出しスレッドは、ほかの読み取りスレッドまたは書き込みスレッドが rwlock という読み取り/書き込みロックを保持していない場合、書き込みロックを獲得します。ほかのスレッドによるロック解除を待たなければロックを獲得できない場合、この待機は、指定されたタイムアウトの期限が切れると終了します。タイムアウトの期限が切れるのは、abs_timeout で指定された絶対時間 (CLOCK_REALTIME クロックで測定される) が経過した場合 (つまり、そのクロックの値が abs_timeout に等しくなるか、超えた場合)、または呼び出し時に abs_timeout で指定された絶対時間がすでに過ぎている場合です。pthread_rwlock_reltimedwrlock_np() 関数は、タイムアウトが相対時間間隔として指定される点を除いて、pthread_rwlock_timedwrlock() 関数と同じ動作をします。

pthread_rwlock_timedwrlock の戻り値

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


ETIMEDOUT

説明:

指定されたタイムアウトの期限が切れる前にロックを獲得できませんでした。


EDEADLK

説明:

呼び出しスレッドは、rwlock をすでに保持しています。


EINVAL

説明:

rwlock で指定された値が初期化された読み取り/書き込みロックオブジェクトを表していないか、タイムアウトのナノ秒の値が 0 未満または 10 億以上です。

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

pthread_rwlock_unlock(3C) は、rwlock が参照する読み取り/書き込みロックオブジェクトに保持されたロックを解放します。

pthread_rwlock_unlock の構文

#include <pthread.h>

int pthread_rwlock_unlock (pthread_rwlock_t  *rwlock);

呼び出しスレッドが rwlock という読み取り/書き込みロック を保持していない場合、その結果は不定です。

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

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

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

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

pthread_rwlock_unlock の戻り値

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

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

pthread_rwlock_destroy(3C) は、rwlock が参照する読み取り/書き込みロックオブジェクトを削除し、このロックが使用していたすべてのリソースを解放します。

pthread_rwlock_destroy の構文

#include <pthread.h>

int pthread_rwlock_destroy(pthread_rwlock_t **rwlock);

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

pthread_rwlock_destroy の戻り値

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


EINVAL

説明:

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