pthread_key_create, pthread_key_delete, pthread_setspecific, pthread_getspecific
-
スレッド固有データの管理
#include <pthread.h>
int pthread_key_create(pthread_key_t *key, void
(*destr_function) (void *));
int pthread_key_delete(pthread_key_t key);
int pthread_setspecific(pthread_key_t key, const void
*pointer);
void * pthread_getspecific(pthread_key_t key);
プログラムではスレッドごとに値の異なる
グローバル変数や静的変数がしばしば必要となる。
複数のスレッドは 1
つのメモリ空間を共有するため、
通常の変数ではこれを実現することができない。
スレッド固有データは、
この必要性への POSIX
スレッドの答えである。
それぞれのスレッドはスレッド固有データ
(thread-specific data) 領域、 略して TSD
領域という
プライベートなメモリブロックを保有している。
この領域は TSD
キーをインデックスとして管理される。
TSD 領域では
void *
型の値を TSD
キーに結び付ける。 TSD
キーはすべてのスレッドに共通であるが、
TSD
キーに結び付けられる値はスレッドごとに異なるように
することができる。
具体的にいえば、 TSD
領域は
void *
型のポインタの配列として、
TSD
キーはこの配列に対する整数値のインデックスとして、
TSD
キーに結び付けられる値は呼び出しスレッドの対応する配列要素として見える。
スレッドが生成されると、TSD
領域はすべてのキーに対する値が
NULL
になるよう初期化される。
pthread_key_create は新しい TSD
キーを確保する。
キーは
key
で指し示される領域に格納される。
ある時点で確保できるキーの数には制限があり、
その最大値は
PTHREAD_KEYS_MAX
である。
返されたキーに結び付けられる初期値は、
その時点で実行されているスレッドすべてにおいて
NULL である。
引数
destr_function に
NULL
以外の値を指定することで、
そのキーに対応するデストラクタ関数を登録することができる。
スレッドが
pthread_exit
やキャンセルによって終了すると、
そのスレッド中でキーに結び付けられた値を引数として関数
destr_function
が呼び出される。
値が
NULL
の場合には関数
destr_function
は呼び出されない。
スレッド終了時にデストラクタ関数が呼び出される順序は不定である。
デストラクタ関数が呼び出される前に、
現在のスレッドにおいてキーに結び付けられる値は
NULL になる。
しかし、デストラクタ関数は
NULL
以外の値をそのキーやほかのキーに結び付けるかもしれない。
これを処理するため、
すべての非
NULL
の値に対するデストラクタ関数をすべて呼び出したあとに
デストラクタ関数のある非
NULL
の値がまだ残っている場合には、
デストラクタ関数の呼び出し処理は繰り返される。
LinuxThreads の実装では、
PTHREAD_DESTRUCTOR_ITERATIONS
回繰り返すと、たとえデストラクタ関数のある非
NULL
の値が残っていても、
処理は中止される。LinuxThreads
以外の実装では無限ループに陥るかもしれない。
pthread_key_delete は TSD
キーを解放する。
その時点で実行中のスレッドでキーに非
NULL
の値が結び付けられているかどうかをチェックしたり、
キーに対応するデストラクタ関数を呼び出したりはしない。
pthread_setspecific
は呼び出しスレッドで
key
に結び付けられる値を、与えられた
pointer に変更する。
pthread_getspecific
は呼び出しスレッドでその時点で
key
に結び付けられている値を返す。
pthread_key_create および
pthread_key_delete
、
pthread_setspecific
は成功すると 0
を、失敗すると非 0
のエラーコードを返す。
成功の場合、
pthread_key_create
は新しく確保されたキーを
引数
key
で指し示される領域に格納する。
pthread_getspecific
は、成功するとキー
key
に結び付けられた値を、
エラーの場合には
NULL
を返す。
pthread_key_create
はエラーの場合に次のようなエラーコードを返す:
- EAGAIN
-
PTHREAD_KEYS_MAX
だけのキーがすでに確保されている。
pthread_key_delete および
pthread_setspecific
はエラーの場合に次のようなエラーコードを返す:
- EINVAL
-
key
は有効な、確保された
TSD キーではない。
pthread_getspecific は、
key
が有効な、確保された
TSD キーでない場合には
NULL を返す。
Xavier Leroy <
[email protected]>
pthread_create(3),
pthread_exit(3),
pthread_testcancel(3).
次のコードでは、100
バイトのスレッド固有の配列を確保し、
スレッドの終了とともに自動で解放する:
/* スレッド固有バッファのキー */
static pthread_key_t buffer_key;
/* 1 回限りのキーの初期化 */
static pthread_once_t buffer_key_once = PTHREAD_ONCE_INIT;
/* スレッド固有のバッファを確保する */
void buffer_alloc(void)
{
pthread_once(&buffer_key_once, buffer_key_alloc);
pthread_setspecific(buffer_key, malloc(100));
}
/* スレッド固有のバッファを返す */
char * get_buffer(void)
{
return (char *) pthread_getspecific(buffer_key);
}
/* キーを確保する */
static void buffer_key_alloc()
{
pthread_key_create(&buffer_key, buffer_destroy);
}
/* スレッド固有のバッファを解放する */
static void buffer_destroy(void * buf)
{
free(buf);
}