在分配线程私有数据之前,需要创建与该数据关联的键,然后每个线程就能独立地设定或取得自己的键值。键对所有的线程是相同的,但每个线程能将它独立的键值与共享的键关联。每个线程能在任何时间为键设置它的私有值,而不会影响到其他线程的键值。线程通常使用malloc 为线程私有数据分配内存空间,析构函数通常释放以分配的内存,如果线程没有释放内存就退出了,则会造成内存泄露。
/* 线程私有数据 */ /* * 函数功能:为线程私有数据创建键值; * 返回值:若成功则返回0,否则返回错误编码; * 函数原型: */ #include <pthread.h> int pthread_key_create(pthread_key_t *keyp, void(*destructor)(void*)); /* * 说明: * 创建的键值存储在keyp所指向的内存单元中,这个键可以被进程中的所以线程使用,但每个线程把这个键 * 与不同的线程私有数据地址进行关联;创建新键时,每个线程的数据地址设为null; * 该函数还包含一个键关联析构函数,当线程退出时,若数据地址为非null,则调用析构函数,唯一的参数就是数据地址; * 若destructor为null时,表示没有析构函数; */ /* * 函数功能:取消线程私有数据与键之间的关联; * 返回值:若成功则返回0,否则返回错误编码; * 函数原型: */ #include <pthread.h> int pthread_key_delete(pthread_key_t *key);对于每个 pthread_key_t 变量只能有一个 pthread_key_create 调用与之对应,如果一个键创建了两次,第二次创建的键将覆盖第一次,第一次的键和任何线程为其设置的值都将丢失。
#include<pthread.h> pthread_once_t initflag = PTHREAD_ONCE_INIT; int pthread_once(pthread_once_t *initflag, void(*initfn)(void)); //成功则返回0,否则返回错误编号。
initfalg 必须是一个全局变量或静态变量,而且必须初始化为PTHREAD_ONCE_INIT。它被称之为控制变量,pthread_once 的第二个参数就是与控制变量关联的函数指针,它所指的函数没有参数。
pthread_once 首先检查控制变量,以判断是否已经完成初始化。如果完成,pthread_once 简单地返回;否则,pthread_once 调用初始化函数。如果一个线程在初始化过程中,另外的线程也调用了pthread_once,这后者将等待,直到前面的线程初始化完成。
键一旦创建,就可以用过调用pthread_setspecific函数把键和线程私有数据关联起来,可以通过pthread_getspecific函数获取线程私有数据的地址。
include <pthread.h> void *pthread_getspecific(pthread_key_t key); //返回值:线程私有数据值,若没有值与键关联则返回NULL int pthread_setspecific(pthread_key_t key, const void *value); //返回值:若成功则返回0,否则返回错误编号
#include "apue.h" #include <pthread.h> extern char **environ; pthread_mutex_t env_mutex; static pthread_key_t key; static pthread_once_t init_done = PTHREAD_ONCE_INIT; static void thread_init(void); char *Mgetenv(const char *name); void *fun1(void *arg); void *fun2(void *arg); int main() { pthread_t tid1,tid2; int err; void *pret; err = pthread_create(&tid1,NULL,fun1,NULL); if(err != 0) err_quit("can't create thread: %s\n", strerror(err)); err = pthread_create(&tid2,NULL, fun2,NULL); if(err != 0) err_quit("can't create thread: %s\n", strerror(err)); pthread_join(tid1,&pret); printf("thread 1 exit code is: %d\n",(int)pret); pthread_join(tid2,&pret); printf("thread 2 exit code is: %d\n",(int)pret); exit(0); } static void thread_init(void) { pthread_mutexattr_t attr; pthread_mutexattr_init(&attr); pthread_mutexattr_settype(&attr,PTHREAD_MUTEX_RECURSIVE); pthread_mutex_init(&env_mutex,&attr); pthread_mutexattr_destroy(&attr); pthread_key_create(&key,free); } char *Mgetenv(const char *name) { int i,len; char *envbuf; pthread_once(&init_done,thread_init); pthread_mutex_lock(&env_mutex); envbuf = (char*)pthread_getspecific(key); if(envbuf == NULL) { envbuf = (char*)malloc(ARG_MAX); if(envbuf == NULL) { pthread_mutex_unlock(&env_mutex); return NULL; } pthread_setspecific(key,envbuf); } len = strlen(name); for(i=0; environ[i] != NULL; i++) { if((strncmp(name, environ[i], len) == 0) && (environ[i][len] == '=')) { strcpy(envbuf, &environ[i][len+1]); pthread_mutex_unlock(&env_mutex); return envbuf; } } pthread_mutex_unlock(&env_mutex); return NULL; } void *fun1(void *arg) { char *value; printf("thread 1 start...\n"); value = Mgetenv("HOME"); printf("HOME=%s\n",value); printf("thread 1 exit...\n"); pthread_exit((void*)1); } void *fun2(void *arg) { char *value; printf("thread 2 start...\n"); value = Mgetenv("SHELL"); printf("SHELL=%s\n",value); printf("thread 2 exit...\n"); pthread_exit((void*)2); }
参考资料:
《UNIX高级环境编程》
http://www.cnblogs.com/Anker/archive/2012/12/19/2824990.html