16

私は POSIX スレッドについて学んでおり、スレッド固有のデータに関するセクションに来ました。この本は、ファイル記述子を使用した優れた例を示しています。ただし、今回はグローバル変数を使用することを除いて、同じ例を自分で実行したかったのです。しかし、私はこの概念を完全に理解するのに苦労しています。

私がやりたいことは次のとおりです。

  • グローバル整数を作成する
  • グローバル int のキーを宣言する

主に:

  • グローバル整数を値に設定します。10
  • クリーンアップせずにキーを作成します
  • 4 つのスレッドを作成し、それらを送信して thread_func を実行します
  • スレッドはそのコピーのみを参照するため、値がまだ 10 であるかどうかを確認します

thread_func で:

  • pthread_setspecific(key,global variable) を使用してローカル インスタンスを作成します - これを正しく解釈しているかどうかわかりません
  • 関数を呼び出す - dosomething()
  • 出口

do_something で

  • ローカル ポインターを作成し、それを pthread_getspecific(key) に割り当てます。これにより、グローバル変数のスレッド固有のバージョンが取得されます。
  • ローカル ポインタに格納されている値を 2 に変更します
  • 出口

コードは次のとおりです。

#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を実行するときに各スレッドのメモリアドレスを調べようとすると、同じメモリアドレスが表示されました. おそらく、誰かがグローバル変数 (ファイル記述子ではなく) を使用し、スレッドがそれをローカル変数と見なすスレッド固有の使用法を持っている例を教えてくれるでしょう。

4

3 に答える 3

20

これは答えではありませんが、補足:

Linux 固有のコードで作業している場合は、__threadキーワードを使用できます。本質的に、

static __thread int counter = 5;

スレッドごとに異なるcounter変数を作成し、新しいスレッドが作成されるたびに値 5 に初期化します。_Thread_localC11 はキーワードを使用して同じセマンティクスを標準化したため、このようなコードは C11 と将来的に互換性があります。これは、__threadC99 以降の " standard non grata " (つまり、 、マイクロソフト)。

詳細については、GCC ドキュメントのスレッドローカルストレージの章を参照してください。

于 2013-02-27T12:05:00.863 に答える
19

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
于 2013-02-26T23:07:12.837 に答える
4

一般的に、探しているのは「スレッド ローカル ストレージ」です。ここにいくつかのリンクがあります:

選ぶpthread_getspecific()のは正しい。良い例を次に示します。

上記の例を確認してください。問題を指摘するか、適切な代替案を提案すると思います。

私見では...

于 2013-02-26T22:50:09.687 に答える