私はPOSIXスレッドについて学び、スレッド固有のデータのセクションに来ました。この本は、ファイル記述子を使用した優れた例を示しています。ただし、今回はグローバル変数を使用することを除いて、同じ例を自分で実行したかったのです。しかし、私はこの概念を完全に理解するのに少し苦労しています。
私がやりたいことは次のとおりです。
主に:
thread_func内:
do_somethingで
コードは次のとおりです。
#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
#define NUMTHREADS 4
pthread_key_t glob_var_key;
int glob_var;
void do_something()
{
//get thread specific data
int* glob_spec_var = (int*) pthread_getspecific(glob_var_key);
printf("Thread %d glob_spec before mod value is %d\n", (unsigned int) pthread_self(), *glob_spec_var);
*glob_spec_var = 2;
printf("Thread %d glob_spec after mod value is %d\n", (unsigned int) pthread_self(), *glob_spec_var);
}
void* thread_func(void *arg)
{
pthread_setspecific(glob_var_key, &glob_var);
do_something();
pthread_exit(NULL);
}
int main(void)
{
pthread_t threads[NUMTHREADS];
int i;
glob_var = 10;
pthread_key_create(&glob_var_key,NULL);
printf("Main: glob_var is %d\n", glob_var);
for (i=0; i < NUMTHREADS; i++)
{
pthread_create(&threads[i],NULL,thread_func,NULL);
}
for (i=0; i < NUMTHREADS; i++)
{
pthread_join(threads[i], NULL);
}
printf("Main: glob_var is %d\n", glob_var);
return 0;
}
私が理解したことから、pthread_getspecificを呼び出すと、各スレッドはメモリアドレス用に独自の一意のメモリアドレスを持っているはずです-ここではそうではありませんでした。私はこれについて正しく行っていないことを知っています。getspecificを実行するときに各スレッドのメモリアドレスを調べようとすると、同じメモリアドレスが表示されました。おそらく誰かが私に、(ファイル記述子ではなく)グローバル変数を使用し、スレッドがそれをローカル変数と見なすスレッド固有の使用法がある例を指摘することができます。
TLS(スレッドローカルストレージ)の目的は、コードがすべてのスレッドで既知の共有キーによってアクセスされるデータベースに格納されているスレッド固有のデータを取得できるようにする定義済みのメカニズムを提供することです。あなたのコードは同じデータをTLSに保存しています:単一のグローバル変数のアドレス)。したがって、スレッドがtls-keyを使用してこのデータを要求すると、それらはすべて同じアドレスを返します。
私はあなたのコードがこのようなことをするつもりだと思います:
#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
#define NUMTHREADS 4
pthread_key_t glob_var_key;
void do_something()
{
//get thread specific data
int* glob_spec_var = pthread_getspecific(glob_var_key);
printf("Thread %d before mod value is %d\n", (unsigned int) pthread_self(), *glob_spec_var);
*glob_spec_var += 1;
printf("Thread %d after mod value is %d\n", (unsigned int) pthread_self(), *glob_spec_var);
}
void* thread_func(void *arg)
{
int *p = malloc(sizeof(int));
*p = 1;
pthread_setspecific(glob_var_key, p);
do_something();
do_something();
pthread_setspecific(glob_var_key, NULL);
free(p);
pthread_exit(NULL);
}
int main(void)
{
pthread_t threads[NUMTHREADS];
int i;
pthread_key_create(&glob_var_key,NULL);
for (i=0; i < NUMTHREADS; i++)
pthread_create(threads+i,NULL,thread_func,NULL);
for (i=0; i < NUMTHREADS; i++)
pthread_join(threads[i], NULL);
return 0;
}
出力
Thread 2625536 before mod value is 1
Thread 741376 before mod value is 1
Thread 3162112 before mod value is 1
Thread 3698688 before mod value is 1
Thread 2625536 after mod value is 2
Thread 741376 after mod value is 2
Thread 3162112 after mod value is 2
Thread 3698688 after mod value is 2
Thread 2625536 before mod value is 2
Thread 741376 before mod value is 2
Thread 3162112 before mod value is 2
Thread 3698688 before mod value is 2
Thread 2625536 after mod value is 3
Thread 741376 after mod value is 3
Thread 3162112 after mod value is 3
Thread 3698688 after mod value is 3
これは答えではありませんが、補足事項です。
Linux固有のコードで作業している場合は、__thread
キーワードを使用できます。基本的に、
static __thread int counter = 5;
スレッドごとに異なるcounter
変数を作成し、新しいスレッドが作成されるたびに値5に初期化されます。 C11は_Thread_local
キーワードを使用して同じセマンティクスを標準化したため、このようなコードはC11と将来互換性があります。これは、C99以降を宣言したアーキテクチャを除くCを使用するすべてのアーキテクチャで、POSIXスレッド固有の関数(実装固有の制限があり、__thread
キーワードと比較して非常に面倒です)よりもはるかに賢明です。 標準の非無償 "(つまり、Microsoft)。
詳細については、 スレッドローカルストレージの章 in GCCドキュメント を参照してください。
一般的に、あなたが探しているのは「スレッドローカルストレージ」です。ここにいくつかのリンクがあります:
pthread_getspecific()
の選択は正しいです。これが良い例です:
上記の例を確認してください。問題を指摘するか、適切な代替案を提案すると思います。
私見では...