多线程私有数据pthread_key_create
参照:http://blog.csdn.net/xiaohuangcat/article/details/18267561
在多线程的环境下,进程内的所有线程共享进程的数据空间。因此全局变量为所有线程共享。在程序设计中有时需要保存线程自己的全局变量,这种特殊的变量仅在线程内部有效。
如常见的errno,它返回标准的错误码。errno不应该是一个局部变量。几乎每个函数都应该可以访问他,但他又不能作为是一个全局变量。否则在一个线程里输出的很可能是另一个线程的
出错信息,这个问题可以通过创建线程的私有数据(TSD thread specific data)来解决。在线程内部,私有数据可以被各个函数访问。但他对其他线程是屏蔽的。
线程私有数据采用了一键多值的技术,即一个键对应多个值。访问数据时都是通过键值来访问,好像是对一个变量进行访问,其实是在访问不同的数据。
int pthread_key_create(pthread_key_t *key, void (*destructor)(void*));第一个参数为指向一个键值的指针,第二个参数指明了一个destructor函数,
如果这个参数不为空,那么当每个线程结束时,系统将调用这个函数来释放绑定在这个键上的内存块。
key一旦被创建,所有线程都可以访问它,但各线程可根据自己的需要往key中填入不同的值,这就相当于提供了一个同名而不同值的全局变量,一键多值。
一键多值靠的是一个关键数据结构数组即TSD池,创建一个TSD就相当于将结构数组中的某一项设置为“in_use”,并将其索引返回给*key,然后设置清理函数。
1、创建一个键
2、为一个键设置线程私有数据
3、从一个键读取线程私有数据void *pthread_getspecific(pthread_key_t key);
4、线程退出(退出时,会调用destructor释放分配的缓存,参数是key所关联的数据)
5、删除一个键
int pthread_setspecific(pthread_key_t key,const void *pointer));
void *pthread_getspecific(pthread_key_t key);
set是把一个变量的地址告诉key,一般放在变量定义之后,get会把这个地址读出来,然后你自己转义成相应的类型再去操作,注意变量的有效期。
只不过,在不同的线程里可以操作同一个key,他们不会冲突,比如线程a,b,c set同样的key,分别get得到的地址会是之前各自传进去的值。
这样做的意义在于,可以写一份线程代码,通过key的方式多线程操作不同的数据。
int pthread_setspecific(pthread_key_t key, const void *value);该函数将value的值(不是内容)与key相关联。用pthread_setspecific为一个键指定新的线程数据时,线程必须先释放原有的线程数据用以回收空间。
nt pthread_key_delete(pthread_key_t key);用来删除一个键,删除后,键所占用的内存将被释放。注销一个TSD,这个函数并不检查当前是否有线程正使用该TSD,也不会调用清理函数(destr_function),
而只是将TSD释放以供下一次调用pthread_key_create()使用。需要注意的是,键占用的内存被释放。与该键关联的线程数据所占用的内存并不被释放。因此,线程数据的释放,必须在释放键之前完成。
简单的示例代码:
#include <pthread.h>
#include <stdio.h> pthread_key_t key;
pthread_t thid1;
pthread_t thid2; void* thread2(void* arg)
{
printf("thread:%lu is running\n", pthread_self()); int key_va = ; pthread_setspecific(key, (void*)key_va); printf("thread:%lu return %d\n", pthread_self(), (int)pthread_getspecific(key));
} void* thread1(void* arg)
{
printf("thread:%lu is running\n", pthread_self()); int key_va = ; pthread_setspecific(key, (void*)key_va); pthread_create(&thid2, NULL, thread2, NULL); printf("thread:%lu return %d\n", pthread_self(), (int)pthread_getspecific(key));
} int main()
{
printf("main thread:%lu is running\n", pthread_self()); pthread_key_create(&key, NULL); pthread_create(&thid1, NULL, thread1, NULL); pthread_join(thid1, NULL);
pthread_join(thid2, NULL); int key_va = ;
pthread_setspecific(key, (void*)key_va); printf("thread:%lu return %d\n", pthread_self(), (int)pthread_getspecific(key)); pthread_key_delete(key); printf("main thread exit\n");
return ;
}
释放空间、每次设置之前判断的代码:
/*三个线程:主线程,th1,th2各自有自己的私有数据区域
*/
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <pthread.h> static pthread_key_t str_key;
//define a static variable that only be allocated once
static pthread_once_t str_alloc_key_once=PTHREAD_ONCE_INIT;
static void str_alloc_key();
static void str_alloc_destroy_accu(void* accu); char* str_accumulate(const char* s)
{ char* accu; pthread_once(&str_alloc_key_once,str_alloc_key);//str_alloc_key()这个函数只调用一次
accu=(char*)pthread_getspecific(str_key);//取得该线程对应的关键字所关联的私有数据空间首址
if(accu==NULL)//每个新刚创建的线程这个值一定是NULL(没有指向任何已分配的数据空间)
{ accu=malloc();//用上面取得的值指向新分配的空间
if(accu==NULL) return NULL;
accu[]=;//为后面strcat()作准备 pthread_setspecific(str_key,(void*)accu);//设置该线程对应的关键字关联的私有数据空间
printf("Thread %lx: allocating buffer at %p\n",pthread_self(),accu);
}
strcat(accu,s);
return accu;
}
//设置私有数据空间的释放内存函数
static void str_alloc_key()
{ pthread_key_create(&str_key,str_alloc_destroy_accu);/*创建关键字及其对应的内存释放函数,当进程创建关键字后,这个关键字是NULL。之后每创建一个线程os都会分给一个对应的关键字,关键字关联线程私有数据空间首址,初始化时是NULL*/
printf("Thread %lx: allocated key %d\n",pthread_self(),str_key);
}
/*线程退出时释放私有数据空间,注意主线程必须调用pthread_exit()(调用exit()不行)才能执行该函数释放accu指向的空间*/
static void str_alloc_destroy_accu(void* accu)
{ printf("Thread %lx: freeing buffer at %p\n",pthread_self(),accu);
free(accu);
}
//线程入口函数
void* process(void *arg)
{ char* res;
res=str_accumulate("Resule of ");
if(strcmp((char*)arg,"first")==)
sleep();
res=str_accumulate((char*)arg);
res=str_accumulate(" thread");
printf("Thread %lx: \"%s\"\n",pthread_self(),res);
return NULL;
}
//主线程函数
int main(int argc,char* argv[])
{ char* res;
pthread_t th1,th2;
res=str_accumulate("Result of ");
pthread_create(&th1,NULL,process,(void*)"first");
pthread_create(&th2,NULL,process,(void*)"second");
res=str_accumulate("initial thread");
printf("Thread %lx: \"%s\"\n",pthread_self(),res);
pthread_join(th1,NULL);
pthread_join(th2,NULL);
pthread_exit();
}
多线程私有数据pthread_key_create的更多相关文章
- linux多线程学习笔记六--一次性初始化和线程私有数据【转】
转自:http://blog.csdn.net/kkxgx/article/details/7513278 版权声明:本文为博主原创文章,未经博主允许不得转载. 一,一次性初始化 以保证线程在调用资源 ...
- 【C/C++多线程编程之十】pthread线程私有数据
多线程编程之线程私有数据 Pthread是 POSIX threads 的简称.是POSIX的线程标准. 线程同步从相互排斥量[C/C++多线程编程之六]pthread相互排 ...
- posix多线程--线程私有数据
1.当多个线程共享一个变量时,将该变量定义为静态或外部变量,使用互斥量确保共享变量的安全访问.如果每个线程都需要一个私有变量值,则该值成为线程的私有数据.程序创建一个键,每个线程独立地设定或得到自己的 ...
- Posix线程编程指南(2) 线程私有数据
概念及作用 在单线程程序中,我们经常要用到"全局变量"以实现多个函数间共享数据.在多线程环境下,由于数据空间是共享的,因此全局变量也为所有线程所共有.但有时应用程序设计中有必要提供 ...
- 浅谈POSIX线程的私有数据
当线程中的一个函数需要创建私有数据时,该私有数据在对函数的调用之间保持一致,数据能静态地分配在存储器中,当我们采用命名范围也许可以实现它使用在函数或是文件(静态),或是全局(EXTERN).但是当涉及 ...
- pthread线程私有数据
进程内所有的线程共享地址空间,任何声明为静态或外部的变量,或在进程堆声明的变量都可以被进程内的所有线程读写. static,extern,或堆变量的值是上次线程改写的值 一个线程真正拥有的唯一私有存储 ...
- Linux系统编程——线程私有数据
在多线程程序中.常常要用全局变量来实现多个函数间的数据共享.因为数据空间是共享的,因此全局变量也为全部线程共同拥有. 測试代码例如以下: #include <stdio.h> #inclu ...
- Thread-specific data(TSD)线程私有数据
Thread-specific data(TSD)线程私有数据 http://blog.chinaunix.net/uid-26885237-id-3209913.html linux多线程编程中引入 ...
- 线程私有数据TSD——一键多值技术,线程同步中的互斥锁和条件变量
一:线程私有数据: 线程是轻量级进程,进程在fork()之后,子进程不继承父进程的锁和警告,别的基本上都会继承,而vfork()与fork()不同的地方在于vfork()之后的进程会共享父进程的地址空 ...
随机推荐
- 微信小程序——3、逻辑js文件
逻辑层js文件 微信小程序前端进行了层次划分,分为逻辑层和视图层.逻辑层实现对数据的加工和处理.与HTML页面相似,逻辑层使用JavaScript编写.逻辑层将数据处理后发送至视图层,同时接受视图层的 ...
- vs下C++内存泄露检测
本文原链接: http://www.cnblogs.com/zouzf/p/4152279.html 参考文章: http://msdn.microsoft.com/zh-cn/library/x98 ...
- Duilib 实现开关按钮
转载:http://blog.csdn.net/wuan584974722/article/details/25045737 我们在做MFC程序时候经常会一个切换式的按钮,之前我的做法是利用butti ...
- Pycharm 2017 激活码
Pycharm 2017 激活码 server选项里边输入: http://idea.liyang.io 我是通过这个成功的
- MAC BOOK Air 安装metasploit-framework
Step 1:Xcode命令行开发工具OS X确保它已经安装了Xcode开发工具,在终端执行: xcode-select --install1Step 2:Java SDK安装Java sdk,不能用 ...
- Codeforces Round #527 (Div. 3)
一场div3... 由于不计rating,所以打的比较浪,zhy直接开了个小号来掉分,于是他AK做出来了许多神仙题,但是在每一个程序里都是这么写的: 但是..sbzhy每题交了两次,第一遍都是对的,结 ...
- sql server 存储过程 procedure
https://www.cnblogs.com/selene/p/4483612.html
- hdu 5668 Circle 中国剩余定理
Circle Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/65536 K (Java/Others) Problem D ...
- PCH Warning: header stop cannot be in a macro or #if block.
在编写头文件时,遇到这么一个warning:PCH Warning: header stop cannot be in a macro or #if block. An intellisense PC ...
- c++ 判断数组元素是否有负数(any_of)
#include <iostream> // std::cout #include <algorithm> // std::any_of #include <array& ...