posix多线程--线程私有数据
1.当多个线程共享一个变量时,将该变量定义为静态或外部变量,使用互斥量确保共享变量的安全访问。
如果每个线程都需要一个私有变量值,则该值成为线程的私有数据。程序创建一个键,每个线程独立地设定或得到自己的键值,各线程间私有数据互不影响。
2.建立线程私有数据
int pthread_key_create(pthread_key_t *key,void (*destructor)(void *));
int pthread_key_delete(pthread_key_t key);
int pthread_setspecific(pthread_key_t key,void *value);
void *pthread_getspecific(pthread_key_t key);
私有数据键,若多次创建,会覆盖掉前面创建的键,对应的键值也将永远丢失。
使用pthread_key_delete释放一个私有数据键时,必须保证所有线程都不在持有该键的值。
更好的做法是不释放线程私有数据键,因为线程私有数据键最多可达128个,很少有程序需要这么多的树木,没有必要手动释放。
代码示例如下:
创建数据键,设置键值,获取键值
#include<stdio.h> #include<pthread.h> typedef struct tsd_tag { pthread_t tid; char *string; }tsd_t; pthread_key_t tsd_key; pthread_once_t key_once = PTHREAD_ONCE_INIT; void one_routine(void) { pthread_key_create(&tsd_key,NULL);; } void *thread_routine(void *arg) { pthread_once(&key_once,one_routine); tsd_t *value; value = (tsd_t*)malloc(sizeof(tsd_t)); pthread_setspecific(tsd_key,value); value->tid = pthread_self(); value->string = (char*)arg; value=(tsd_t*)pthread_getspecific(tsd_key); sleep(2); value=(tsd_t*)pthread_getspecific(tsd_key); printf("%s done...\n",value->string); } int main(void) { pthread_t tid1,tid2; pthread_create(&tid1,NULL,thread_routine,"thread 1"); pthread_create(&tid2,NULL,thread_routine,"thread 2"); pthread_exit(NULL); }
3.destructor函数
destructor函数仅仅当线程终止时被调用。当线程终止时,pthreads调用键的destructor函数前,将线程私有数据置为NULL,所以若线程私有数据值是堆存储的地址,并且想在destructor函数中释放,必须使用传递给destructor的参数,而不是pthread_getspecific的参数。可以自定义destructor函数。
键值为NULL意味着线程对应该键值不再有值,而不是赋空值。否则若随后调用pthread_key_create建立该键,线程将会收到旧值。
线程私有数据键的destructor函数在键值替换的时候不会被调用。即,如果在堆中将一个结构的指针作为键值,又分配一个新结构,并将新结构指针赋给相同数据键,则指向旧结构的指针不会调用destructor函数。
代码示例如下:
三个线程的私有变量数据,自定义destructor函数,在线程结束后,释放堆存储,在所有线程结束后,销毁私有数据键。
#include<stdio.h> #include<pthread.h> typedef struct private_tag { pthread_t tid; char *string; }private_t; pthread_key_t key; pthread_mutex_t mutex=PTHREAD_MUTEX_INITIALIZER; long counter = 0; void key_destructor(void *value) { private_t *private = (private_t*)value; printf("thread \"%s\" exiting...\n",private->string); free(value); pthread_mutex_lock(&mutex); counter--; if(counter<=0) { pthread_key_delete(key); printf("key deleted...\n"); } pthread_mutex_unlock(&mutex); } void *key_get(void) { void *value; value = pthread_getspecific(key); if(value==NULL) { printf("malloc\n"); value = malloc(sizeof(private_t)); pthread_setspecific(key,(void*)value); } return value; } void *thread_routine(void *arg) { private_t *value; value = (private_t*)key_get(); value->tid = pthread_self(); value->string = (char*)arg; printf("thread \"%s\" starting...\n",value->string); sleep(2); return NULL; } int main(void) { pthread_t tid1,tid2; private_t *value; pthread_key_create(&key,key_destructor); counter = 3; value = (private_t *)key_get(); value->tid = pthread_self(); value->string = "Main thread"; pthread_create(&tid1,NULL,thread_routine,"Thread 1"); pthread_create(&tid2,NULL,thread_routine,"Thread 2"); printf("exiting\n"); pthread_exit(NULL); }