How do I create a global variable that is thread-specific in C using POSIX threads?

为君一笑 提交于 2020-01-11 17:07:11

问题


I am learning about POSIX threads and I have come to the section on Thread Specific Data. The book does an excellent example using a file descriptor. However, I wanted to do the same example on my own, except this time using a global variable. However, I am having some difficulty fully grasping this concept.

What I want to do is the following:

  • Create a global integer
  • Declare a key for the global int

in main:

  • set global integer to be a value eg. 10
  • create a key for it without any clean up
  • create 4 threads and send them to execute thread_func
  • check if value is still 10, since threads only see a copy of it

in thread_func:

  • use pthread_setspecific(key,global variable) to create a local instance - not sure if I am interpreting this correctly
  • call a function - dosomething()
  • exit

in do_something

  • create a local pointer and assign it to pthread_getspecific(key) - this should get me a thread specific version of the global variable
  • change the value of what is stored at the local pointer to 2
  • exit

Here's the code:

#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;
}

From what I understood, when you call pthread_getspecific, each thread is supposed to have its own unique memory address for the memory addresses - which I did not find to be the case here. I know I am not going about this correctly and when I did try to look at the memory addresses for each thread when doing getspecific, I saw the same memory address. Perhaps someone can point me to an example where they use a global variable (not file descriptors) and they have thread-specific usage in which threads look at it as a local variable.


回答1:


The purpose of TLS (thread-local storage) is to provide an defined mechanism whereby code can retrieve thread-specific data stored in a database accessed by a all-threads-known shared key. Your code is storing the same data in TLS: the address of a single global variable). Therefore when a thread requests this data using the tls-key, they will all get back the same address.

I think you intend your code to do something like this:

#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;
}

Output

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:


This is not an answer, but a side note:

If you are working on Linux-specific code, you can use the __thread keyword. Essentially,

static __thread int counter = 5;

creates a different counter variable for each thread, initialized to value 5 whenever a new thread gets created. Such code is future-compatible with C11, since C11 standardized the same semantics using the _Thread_local keyword. This is much saner than the POSIX thread-specific functions (which have implementation-specific limits, and are quite cumbersome compared to the __thread keyword), on all architectures using C, except those that have declared C99 and later "standard non grata" (i.e., Microsoft).

See the Thread-Local Storage chapter in GCC documentation for details.




回答3:


In general, what you're looking for is "thread local storage". Here are a few links:

  • http://publib.boulder.ibm.com/infocenter/iseries/v7r1m0/index.jsp?topic=%2Frzahw%2Frzahwex1.htm

  • http://en.wikipedia.org/wiki/Thread-local_storage

Choosing pthread_getspecific() is correct. Here's a good example:

  • http://publib.boulder.ibm.com/infocenter/iseries/v7r1m0/index.jsp?topic=%2Fapis%2Fusers_34.htm

Please review the above example: I think it will point you to the problem ... or suggest a good alternative.

IMHO...



来源:https://stackoverflow.com/questions/15100824/how-do-i-create-a-global-variable-that-is-thread-specific-in-c-using-posix-threa

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!