posixマルチスレッドセンシング--スレッド高度プログラミング(pthread_key_t)
5760 ワード
次にスレッド固有のスレッド格納,Thread Specific Dataについて述べる.スレッドストレージは何に使いますか?どういう意味だ?マルチスレッドプログラムでは、すべてのスレッドがプログラム内の変数を共有していることはよく知られています.グローバル変数があり、すべてのスレッドで使用して値を変更できます.各スレッドが単独で所有したい場合は、スレッドストレージを使用する必要があります.表面的にはグローバル変数のように見え、すべてのスレッドで使用できますが、その値は各スレッドに個別に格納されます.これがスレッドストレージの意味です.
スレッドプライベートデータは、1つのキーが複数の数値に対応する1つのキー多値と呼ばれる技術を採用している.データにアクセスするときはキー値でアクセスしますが、1つの変数にアクセスするようですが、実は異なるデータにアクセスしています.スレッドプライベートデータを使用する場合は、まず各スレッドデータに関連付けられたキーを作成します.各スレッドの内部では、この共通のキーを使用してスレッドデータを指すが、異なるスレッドでは、このキーが表すデータは異なる.操作スレッドのプライベートデータの関数は主に4つあります:pthread_key_create(キーを作成)、pthread_setspecific(キーにスレッドプライベートデータを設定)、pthread_getspecific(1つのキーからスレッドのプライベートデータを読み出す)、pthread_key_delete(キーを削除します).スレッドストレージの具体的な使い方を説明します.1.pthread_のタイプを作成key_tタイプの変数.
2.pthread_を呼び出すkey_create()を使用して変数を作成します.LinuxのTSDプールから、後でアクセスするためにkeyに値を割り当てます.最初のパラメータkeyはキー値を指すポインタで、2番目のパラメータは関数ポインタで、ポインタが空でない場合、スレッド終了時にkeyに関連付けられたデータをパラメータとしてdestructor()を呼び出して割り当てられたバッファを解放します.keyが作成されると、すべてのスレッドがアクセスできますが、各スレッドは自分の必要に応じてkeyに異なる値を入力できます.これは、同じ名前で異なる値を提供するグローバル変数、1つのキーで複数の値に相当します.
3.スレッドに特別な値を格納する必要がある場合、pthread_を呼び出すことができます.setspcific() .この関数には2つのパラメータがあり、1つ目は前に宣言したpthread_です.key_t変数、2番目はvoid*変数で、任意のタイプの値を格納できます.関数はvalueの値(コンテンツではない)をkeyに関連付けます.pthread_でsetspecificがキーに新しいスレッドデータを指定する場合、スレッドはまず既存のスレッドデータを解放して空間を回収する必要があります.
4.格納された値を取り出す必要がある場合はpthread_を呼び出すgetspecific() .この関数のパラメータは、前述のpthread_です.key_t変数で、void*タイプの値を返します.
5.pthread_key_delete:この関数はキーを削除するために使用され、キーに使用されるメモリが解放されます.なお、キーが占有するメモリは解放され、キーに関連付けられたスレッドデータが占有するメモリは解放されない.したがって、スレッドデータの解放は、キーを解放する前に完了する必要があります.次に、前述した関数のプロトタイプを示します.
最後にスレッドの本質を説明します:実はLinuxでは、新しいスレッドは元のプロセスではなく、システムがシステムを通じてclone()を呼び出すのです.このシステムcopyは、元のプロセスと全く同じプロセスを実行し、このプロセスでスレッド関数を実行します.しかし、このcopyプロセスはforkとは違います.copy後のプロセスは元のプロセスとすべての変数を共有し、実行環境(cloneの実装は新しいプロセスと古いプロセスの間の共有関係を指定することができ、100%共有はスレッドを作成したことを示す).これにより,元のプロセスにおける変数がcopyを変動した後のプロセスに現れる.
スレッドプライベートデータは、1つのキーが複数の数値に対応する1つのキー多値と呼ばれる技術を採用している.データにアクセスするときはキー値でアクセスしますが、1つの変数にアクセスするようですが、実は異なるデータにアクセスしています.スレッドプライベートデータを使用する場合は、まず各スレッドデータに関連付けられたキーを作成します.各スレッドの内部では、この共通のキーを使用してスレッドデータを指すが、異なるスレッドでは、このキーが表すデータは異なる.操作スレッドのプライベートデータの関数は主に4つあります:pthread_key_create(キーを作成)、pthread_setspecific(キーにスレッドプライベートデータを設定)、pthread_getspecific(1つのキーからスレッドのプライベートデータを読み出す)、pthread_key_delete(キーを削除します).スレッドストレージの具体的な使い方を説明します.1.pthread_のタイプを作成key_tタイプの変数.
2.pthread_を呼び出すkey_create()を使用して変数を作成します.LinuxのTSDプールから、後でアクセスするためにkeyに値を割り当てます.最初のパラメータkeyはキー値を指すポインタで、2番目のパラメータは関数ポインタで、ポインタが空でない場合、スレッド終了時にkeyに関連付けられたデータをパラメータとしてdestructor()を呼び出して割り当てられたバッファを解放します.keyが作成されると、すべてのスレッドがアクセスできますが、各スレッドは自分の必要に応じてkeyに異なる値を入力できます.これは、同じ名前で異なる値を提供するグローバル変数、1つのキーで複数の値に相当します.
3.スレッドに特別な値を格納する必要がある場合、pthread_を呼び出すことができます.setspcific() .この関数には2つのパラメータがあり、1つ目は前に宣言したpthread_です.key_t変数、2番目はvoid*変数で、任意のタイプの値を格納できます.関数はvalueの値(コンテンツではない)をkeyに関連付けます.pthread_でsetspecificがキーに新しいスレッドデータを指定する場合、スレッドはまず既存のスレッドデータを解放して空間を回収する必要があります.
4.格納された値を取り出す必要がある場合はpthread_を呼び出すgetspecific() .この関数のパラメータは、前述のpthread_です.key_t変数で、void*タイプの値を返します.
5.pthread_key_delete:この関数はキーを削除するために使用され、キーに使用されるメモリが解放されます.なお、キーが占有するメモリは解放され、キーに関連付けられたスレッドデータが占有するメモリは解放されない.したがって、スレッドデータの解放は、キーを解放する前に完了する必要があります.次に、前述した関数のプロトタイプを示します.
pthread_key_t key;
int pthread_create(pthread_key_t,void(*destructor)(void *));
int pthread_key_delete(pthread_key_t key);
int pthread_setspecific(pthread_key_t key,const void *value);
void* pthread_getspecific(pthread_key_t key);
/*
* tsd_destructor.c
*
* Demonstrate use of thread-specific data destructors.
*/
#include <pthread.h>
#include "errors.h"
/*
* Structure used as value of thread-specific data key.
*/
typedef struct private_tag {
pthread_t thread_id;
char *string;
} private_t;
pthread_key_t identity_key; /* Thread-specific data key */
pthread_mutex_t identity_key_mutex = PTHREAD_MUTEX_INITIALIZER;
long identity_key_counter = 0;
/*
* This routine is called as each thread terminates with a value
* for the thread-specific data key. It keeps track of how many
* threads still have values, and deletes the key when there are
* no more references.
*/
void identity_key_destructor (void *value)
{
private_t *private = (private_t*)value;
int status;
printf ("thread \"%s\" exiting...
", private->string);
free (value);
status = pthread_mutex_lock (&identity_key_mutex);
if (status != 0)
err_abort (status, "Lock key mutex");
identity_key_counter--;
if (identity_key_counter <= 0) {
status = pthread_key_delete (identity_key);
if (status != 0)
err_abort (status, "Delete key");
printf ("key deleted...
");
}
status = pthread_mutex_unlock (&identity_key_mutex);
if (status != 0)
err_abort (status, "Unlock key mutex");
}
/*
* Helper routine to allocate a new value for thread-specific
* data key if the thread doesn't already have one.
*/
void *identity_key_get (void)
{
void *value;
int status;
value = pthread_getspecific (identity_key);
if (value == NULL) {
value = malloc (sizeof (private_t));
if (value == NULL)
errno_abort ("Allocate key value");
status = pthread_setspecific (identity_key, (void*)value);
if (status != 0)
err_abort (status, "Set TSD");
}
return value;
}
/*
* Thread start routine to use thread-specific data.
*/
void *thread_routine (void *arg)
{
private_t *value;
value = (private_t*)identity_key_get ();
value->thread_id = pthread_self ();
value->string = (char*)arg;
printf ("thread \"%s\" starting...
", value->string);
sleep (2);
return NULL;
}
void main (int argc, char *argv[])
{
pthread_t thread_1, thread_2;
private_t *value;
int status;
/*
* Create the TSD key, and set the reference counter to
* the number of threads that will use it (two thread_routine
* threads plus main). This must be done before creating
* the threads! Otherwise, if one thread runs the key's
* destructor before any other thread uses the key, it will
* be deleted.
*
* Note that there's rarely any good reason to delete a
* thread-specific data key.
*/
status = pthread_key_create (&identity_key, identity_key_destructor);
if (status != 0)
err_abort (status, "Create key");
identity_key_counter = 3;
value = (private_t*)identity_key_get ();
value->thread_id = pthread_self ();
value->string = "Main thread";
status = pthread_create (&thread_1, NULL,
thread_routine, "Thread 1");
if (status != 0)
err_abort (status, "Create thread 1");
status = pthread_create (&thread_2, NULL,
thread_routine, "Thread 2");
if (status != 0)
err_abort (status, "Create thread 2");
pthread_exit (NULL);
}
最後にスレッドの本質を説明します:実はLinuxでは、新しいスレッドは元のプロセスではなく、システムがシステムを通じてclone()を呼び出すのです.このシステムcopyは、元のプロセスと全く同じプロセスを実行し、このプロセスでスレッド関数を実行します.しかし、このcopyプロセスはforkとは違います.copy後のプロセスは元のプロセスとすべての変数を共有し、実行環境(cloneの実装は新しいプロセスと古いプロセスの間の共有関係を指定することができ、100%共有はスレッドを作成したことを示す).これにより,元のプロセスにおける変数がcopyを変動した後のプロセスに現れる.