精通
英语
和
开源
,
擅长
开发
与
培训
,
胸怀四海
第一信赖
有时在应用程序中使用的全局变量,我们希望它只作用于当前的线程。即我们希望每个子线程有针对它们自身的私有的全局变量,这个全局变量对别的线程不可见,这时就可以使用线程的特有数据(Thread specific data)。这个全局变量由当前线程分配空间,并加以保存。可以为这个全局变量分配一个销毁函数,当当前线程结束时,系统将会自动运行这个销毁函数,来清空当前线程分配的存储空间。我们可以使用线程的特有数据来代替全局变量,因为一个线程中,所有的函数对这片存储空间的请求,都会得到一个相同的值。而其它线程中的函数在相同的语句中访问的,是调用函数的线程自身的存储空间。(也就是线程与线程之间互不干扰)。
与线程的特有数据相关的函数为:在下面这个例子中,定义了一个pthread_key_t 结构的变量tlskey,这个变量虽然是全局变量,但在这个程序的使用中,实际上就是一个线程的特有数据,即它的作用空间仅限于当前线程。
首先,需要使用 pthread_key_create 命令来创建生成这个线程特有数据,同时为这个数据指定一个销毁函数globalDestructor。当子线程结束时,如果tlskey 自身,以及它所指向的数据都不为空的话, 那么系统将会自动运行销毁函数globalDestructor 。同时,pthread_key_create 函数在销毁函数参数不为空的时候,也就相当于将tlskey 指定成为的销毁函数的入口参数,所以在销毁函数中,直接对参数进行free()操作,其实也就是将tlskey 指向的地址空间释放,最后再把这片地址空间赋值为空。
在主线程中,每次创建子线程之前,都先分配一片存储空间,然后就这片空间的指针传递到子线程中;子线程通过pthread_setspecific 函数,将线程特有数据tlskey 指向了这片存储空间。于是,在当前线程中,所有的函数都可以共享这个特有数据tlskey,然后通过这个tlskey 再共享它所指向的存储空间。比如说showdata 函数,就是通过pthread_getspecific 函数使用了tlskey,从而访问到了存储空间中的数据。
当每个子线程结束的时候,系统将会自动运行销毁函数,打印出一句话,然后执行free操作,最后再使用pthread_setspecific 函数,将线程特有数据tlskey 指向的存储空间清空。
#define _MULTI_THREADED
#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#define checkResults(string, val) { \
if (val) { \
printf("Failed with %d at %s", val, string); \
exit(1); \
} \
}
#define NUMTHREADS 3
pthread_key_t tlsKey = 0;
typedef struct {
int data1;
int data2;
} mystruct;
void globalDestructor(void *value)
{
printf("%.8x,%.8x: In the data destructor\n", \
pthread_getthreadid_np());
free(value);
pthread_setspecific(tlsKey, NULL);
}
void showdata()
{
mystruct *gdata;
gdata=pthread_getspecific(tlsKey);
printf("%.8x, %.8x: get data data1= %d, data2=%d\n", \
pthread_getthreadid_np(), gdata->data1, gdata->data2);
}
void *threadfunc(void *parm)
{
mystruct *gdata;
gdata=(mystruct *)parm;
printf("%.8x, %.8x: set data data1= %d, data2=%d\n", \
pthread_getthreadid_np(), gdata->data1, gdata->data2);
pthread_setspecific(tlsKey, gdata);
showdata();
printf("%.8x, %.8x: Ready exit thread, run function destruct\n",
pthread_getthreadid_np());
return NULL;
}
int main(int argc, char **argv)
{
pthread_t thread[NUMTHREADS];
int rc=0;
int i=0;
mystruct *gData;
printf("Enter Testcase - %s\n", argv[0]);
printf("Create a thread local storage key\n");
rc = pthread_key_create(&tlsKey, globalDestructor);
checkResults("pthread_key_create()\n", rc);
/* The key can now be used from all threads */
for(i=0;i<NUMTHREADS;i++){
gData=(mystruct *)malloc(sizeof(mystruct));
gData->data1=i;
gData->data2=(i+1)*i;
pthread_create(&thread[i], NULL, threadfunc, gData);
}
for(i=0;i<NUMTHREADS;i++)
pthread_join(thread[i], NULL);
printf("Delete a thread local storage key\n");
rc = pthread_key_delete(tlsKey);
checkResults("pthread_key_delete()\n", rc);
/* The key and any remaining values are now gone. */
printf("Main completed\n");
return 0;
}