问题
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