linux中一个进程中的线程除了线程自己的栈和寄存器之外,其他几乎都是共享的,如果一个线程想拥有一个只属于线程自己的全局变量怎么办?线程私有存储解决了这个问题。
线程私有存储的具体用法:
1. 声明一个类型为 pthread_key_t 类型的变量。【进程】
2. 调用 pthread_key_create() 来创建该变量,该函数有两个参数,第一个参数就是上面声明的 pthread_key_t 变量,第二个参数是一个清理函数,在线程退出时(调用pthread_exit函数时)调用该函数,以释放分配的缓冲区或者关闭文件流。该函数指针可以设成 NULL ,这样系统将调用默认的清理函数。【进程】
3. 当线程中需要存储特殊值的时候,可以调用 pthread_setspecific() 。该函数有两个参数,第一个为前面声明的 pthread_key_t 变量,第二个为 void* 变量,这样你可以存储任何类型的值。【线程】
4. 如果需要取出所存储的值,调用 pthread_getspecific() 。该函数的参数为前面提到的 pthread_key_t 变量,该函数返回 void * 类型的值。【线程】
pthread_key_t无论是哪一个线程创建,其他所有的线程都是可见的,即一个进程中只需phread_key_create()一次。看似是全局变量,然而全局的只是key值,对于不同的线程对应的value值是不同的(通过pthread_setspcific()和pthread_getspecific()设置)。
int pthread_key_create(pthread_key_t *key, void (*destr_function) (void *))
不论哪个线程调用pthread_key_create(),所创建的key都是所有线程可访问的,但各个线程可根据自己的需要往key中填入不同的值,这就相当于提供了一个同名而不同值的全局变量。
pthread_key_create的原理为从TSD池中分配一项,将其地址赋值给key供以后访问使用。在LinuxThreads的实现中,TSD池用一个结构数组表示:
static struct pthread_key_struct pthread_keys[PTHREAD_KEYS_MAX] = { { 0, NULL } };
创建一个TSD就相当于将结构数组中的某一项设置为"in_use",并将其索引返回给*key,然后设置destructor函数为destr_function。
int pthread_setspecific(pthread_key_t key, const void *pointer)
void * pthread_getspecific(pthread_key_t key)
写入(pthread_setspecific())时,将pointer的值(不是所指的内容)与key相关联,而相应的读出函数则将与key相关联的数据读出来。数据类型都设为void *,因此可以指向任何类型的数据。
注销一个TSD使用pthread_key_delete函数,该函数并不检查当前是否有线程正在使用该TSD,也不会调用清理函数,而只是将TSD释放以供下一次调用pthread_key_create使用。在LinuxThreads中,它还会将与之相关的线程数据项设置为NULL。
#include <stdio.h>
#include <pthread.h>
pthread_key_t key;
void echomsg(int t)
{
printf("destructor excuted in thread %d,param=%d\n",pthread_self(),t);
}
void * child1(void *arg)
{
pthread_t tid=pthread_self();
printf("thread %d enter\n",tid);
pthread_setspecific(key,(void *)tid);
sleep(2);
printf("thread %d returns %d and key %d\n",tid,pthread_getspecific(key),key);
sleep(5);
}
void * child2(void *arg)
{
pthread_t tid=pthread_self();
printf("thread %d enter\n",tid);
pthread_setspecific(key,(void *)tid);
sleep(1);
printf("thread %d returns %d and key %d\n",tid,pthread_getspecific(key),key);
sleep(5);
}
int main(void)
{
pthread_t tid1,tid2;
printf("this is main thread\n");
pthread_key_create(&key,(void (*)(void *))echomsg);
pthread_create(&tid1,NULL,child1,NULL);
pthread_create(&tid2,NULL,child2,NULL);
sleep(10);
pthread_join(tid1, NULL);
pthread_join(tid2, NULL);
pthread_key_delete(key);
printf("main thread exit\n");
return 0;
}