pthread_key_create(3) スレッド固有データの管理

Other Alias

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_functionNULL 以外の値を指定することで、 そのキーに対応するデストラクタ関数を登録することができる。 スレッドが 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_deletepthread_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]>

次のコードでは、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);
}