如何使用POSIX线程在C中创建特定于线程的全局变量?

时间:2013-02-26 22:40:39

标签: c linux multithreading pthreads posix

我正在学习POSIX线程,我已经开始讨论线程特定数据。本书使用文件描述符做了一个很好的例子。但是,我想自己做同样的例子,除了这次使用全局变量。但是,我在完全理解这个概念时遇到了一些困难。

我想做的是以下内容:

  • 创建全局整数
  • 声明global int的键

在main中:

  • 将全局整数设置为例如值。 10
  • 为其创建密钥而不进行任何清理
  • 创建4个线程并将它们发送到执行thread_func
  • 检查值是否仍为10,因为线程只看到它的副本

在thread_func中:

  • 使用pthread_setspecific(键,全局变量)创建本地实例 - 不确定我是否正确解释
  • 调用函数 - 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时,每个线程应该有自己唯一的内存地址的内存地址 - 我在这里没有发现这种情况。我知道我没有正确地解决这个问题,当我在做特定操作时尝试查看每个线程的内存地址时,我看到了相同的内存地址。也许有人可以指出我使用全局变量(不是文件描述符)的示例,并且它们具有特定于线程的用法,其中线程将其视为局部变量。

3 个答案:

答案 0 :(得分:18)

这不是答案,而是旁注:

如果您正在使用特定于Linux的代码,则可以使用__thread关键字。从本质上讲,

static __thread int counter = 5;

为每个线程创建一个不同的counter变量,每当创建一个新线程时,该变量初始化为值5。此类代码与C11未来兼容,因为C11使用_Thread_local关键字标准化了相同的语义。这比使用C的所有体系结构上的POSIX线程专用函数(具有特定于实现的限制,并且与__thread关键字相比非常麻烦)更加安全,除了那些已声明C99及更高版本的< em>标准不受欢迎“(即微软)。

有关详细信息,请参阅Thread-Local Storage chapter中的GCC documentation

答案 1 :(得分:15)

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

答案 2 :(得分:4)

一般来说,您正在寻找的是“线程本地存储”。以下是一些链接:

选择pthread_getspecific()是正确的。这是一个很好的例子:

请查看以上示例:我认为它会指出您的问题......或建议一个好的替代方案。

... IMHO