Linux多线程实践(四 )线程的特定数据
在单线程程序中。我们常常要用到"全局变量"以实现多个函数间共享数据, 然而在多线程环境下。因为数据空间是共享的。因此全局变量也为全部线程所共同拥有。但有时应用程序设计中有必要提供线程私有的全局变量,仅在某个线程中有效,但却能够跨多个函数訪问。POSIX线程库通过维护一定的数据结构来解决问题。这个些数据称为(Thread-specific-data或 TSD)。
相关函数例如以下:
int pthread_key_create(pthread_key_t *key, void (*destr_function) (void *));
int pthread_key_delete(pthread_key_t key); int pthread_setspecific(pthread_key_t key, const void *pointer);
void * pthread_getspecific(pthread_key_t key); pthread_once_t once_control = PTHREAD_ONCE_INIT;
int pthread_once(pthread_once_t *once_control, void (*init_routine) (void));
watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQv/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center" alt="">
从上图可知:当调用pthread_key_create 后会产生一个全部线程都可见的线程特定数据(TSD)的键值(如上图中全部的线程都会得到一个pkey[1]的值), 可是这个键所指向的真实数据却是不同的,尽管都是pkey[1], 可是他们并非指向同一块内存,而是指向了仅仅属于自己的实际数据, 因此, 假设线程0更改了pkey[1]所指向的数据, 而并不可以影像到线程n;
在线程调用pthread_setspecific后会将每一个线程的特定数据与thread_key_t绑定起来,尽管仅仅有一个pthread_key_t。但每一个线程的特定数据是独立的内存空间,当线程退出时会运行destructor 函数。
/** 演示样例1:运用pthread_once, 让key仅仅初始化一次
注意: 将对key的初始化放入到init_routine中
**/
pthread_key_t key;
pthread_once_t once_control = PTHREAD_ONCE_INIT;
typedef struct Tsd
{
pthread_t tid;
char *str;
} tsd_t; //线程特定数据销毁函数,
//用来销毁每一个线程所指向的实际数据
void destructor_function(void *value)
{
free(value);
cout << "destructor ..." << endl;
} //初始化函数, 将对key的初始化放入该函数中,
//能够保证inti_routine函数仅仅执行一次
void init_routine()
{
pthread_key_create(&key, destructor_function);
cout << "init..." << endl;
} void *thread_routine(void *args)
{
pthread_once(&once_control, init_routine); //设置线程特定数据
tsd_t *value = (tsd_t *)malloc(sizeof(tsd_t));
value->tid = pthread_self();
value->str = (char *)args;
pthread_setspecific(key, value);
printf("%s setspecific, address: %p\n", (char *)args, value); //获取线程特定数据
value = (tsd_t *)pthread_getspecific(key);
printf("tid: 0x%x, str = %s\n", (unsigned int)value->tid, value->str);
sleep(2); //再次获取线程特定数据
value = (tsd_t *)pthread_getspecific(key);
printf("tid: 0x%x, str = %s\n", (unsigned int)value->tid, value->str); pthread_exit(NULL);
} int main()
{
pthread_t tid1, tid2;
pthread_create(&tid1, NULL, thread_routine, (void *)"thread1");
pthread_create(&tid2, NULL, thread_routine, (void *)"thread2"); pthread_join(tid1, NULL);
pthread_join(tid2, NULL);
pthread_key_delete(key); return 0;
}
执行结果例如以下:
init....
thread1 setspecific ,address: 0x7fe7a00008c0
tid: 0xa8192700, str = thread1
thread2 setspecific ,address :0x7fe7980008c0
tid: 0xa7991700 ,str = thread2
tid: 0xa8192700 ,str = thread1
tid: 0xa7001700 ,str = thread2
destructor...
destructor...
主线程创建了两个线程然后join 等待他们退出;给每一个线程的运行函数都是thread_routine,thread_routine 中调用了pthread_once,此函数表示假设当第一个线程调用它时会运行once_routine,然后从once_routine返回即pthread_once 返回,而接下去的其它线程调用它时将不再运行once_routine。此举是为了仅仅调用pthread_key_create 一次,即产生一个pthread_key_t
值。
在thread_routine 函数中自己定义了线程特定数据的类型。对于不同的线程来说TSD的内容不同,如果线程1在第一次打印完进入睡眠的时候。线程2也開始运行并调用pthread_setspecific 绑定线程2的TSD 和key_t,此时线程1调用pthread_getspecific 返回key_t 绑定的TSD指针,仍然是线程1的TSD指针,即尽管key_t 仅仅有一个,但每一个线程都有自己的TSD。
特定数据。具有128项,通过key-value实现,一个线程创建一个key,其它线程也会创建。可是并非指向的同一快内存。他们指向自己的数据。
这就是线程特定数据。
上述代码中,即使是Sleeep(2),线程1的数据并不会被线程2的数据所影响。由于是线程私有的。
当线程退出的时候会销毁2次,由于创建了两个线程。
当中tid 是线程的id,str 是传递给thread_routine 的參数,能够看到有两个不同的ptr,且destroy 调用两次。
另外,关于Linux/Unix线程私有数据实现思想:
请參考 http://blog.csdn.net/caigen1988/article/details/7901248。写的非常好。
Linux多线程实践(四 )线程的特定数据的更多相关文章
- Linux多线程实践(4) --线程特定数据
线程特定数据 int pthread_key_create(pthread_key_t *key, void (*destr_function) (void *)); int pthread_key_ ...
- Linux多线程实践(1) --线程理论
线程概念 在一个程序里的一个执行路线就叫做线程(thread).更准确的定义是:线程是"一个进程内部的控制序列/指令序列"; 一切进程至少有一个执行线程; 进程 VS. 线程 ...
- Linux多线程实践(2) --线程基本API
POSIX线程库 与线程有关的函数构成了一个完整的系列,绝大多数函数的名字都是以"pthread_"开头,要使用这些函数库,要通过引入头文<pthread.h>,而且链 ...
- Linux多线程实践(3) --线程属性
初始化/销毁线程属性 int pthread_attr_init(pthread_attr_t *attr); int pthread_attr_destroy(pthread_attr_t *att ...
- Linux多线程实践(一)线程基本概念和理论
线程概念 在一个程序里的一个运行路线就叫做线程(thread).更准确的定义是:线程是"一个进程内部的控制序列/指令序列"; 对于每一个进程至少有一个运行线程; 进程 VS. 线 ...
- Linux多线程实践(10) --使用 C++11 编写 Linux 多线程程序
在这个多核时代,如何充分利用每个 CPU 内核是一个绕不开的话题,从需要为成千上万的用户同时提供服务的服务端应用程序,到需要同时打开十几个页面,每个页面都有几十上百个链接的 web 浏览器应用程序,从 ...
- Linux多线程实践(7) --多线程排序对比
屏障 int pthread_barrier_init(pthread_barrier_t *restrict barrier, const pthread_barrierattr_t *restri ...
- Linux多线程实践(三)线程的基本属性设置API
POSIX 线程库定义了线程属性对象 pthread_attr_t ,它封装了线程的创建者能够訪问和改动的线程属性.主要包含例如以下属性: 1. 作用域(scope) 2. 栈尺寸(stack siz ...
- Linux多线程实践(9) --简单线程池的设计与实现
线程池的技术背景 在面向对象编程中,创建和销毁对象是很费时间的,因为创建一个对象要获取内存资源或者其它更多资源.在Java中更是如此,虚拟机将试图跟踪每一个对象,以便能够在对象销毁后进行垃圾回收.所以 ...
随机推荐
- HDOJ 3339 In Action
最短路+01背包 In Action Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Other ...
- Hdu 4280 Island Transport(最大流)
Island Transport Time Limit: 20000/10000 MS (Java/Others) Memory Limit: 65536/65536 K (Java/Other ...
- Java推断文本文件编码格式以及读取
假设不是约定好的,要想解析txt文件就须要知道文件编码类型,因为文件编码类型众多.比如UTF-8,GBK.UTF-16,GB2312等等. 事实上有简单的办法.仅仅须要这样就能够了 String fi ...
- Oracle 单表选择率
听了猫大师的课,对Oracle CBO又加深了一步理解: 单表选择率: selectivity=1/ndv*a4nulls ocard来自dba_tables.num_rows ndv 来自dba_t ...
- kentico中提示Message: An invalid SQL query was used.
在调用CMSAbstractWebPart类的GetValue方法的时候出错. namespace CMS.PortalEngine.Web.UI{ /// <summary> /// B ...
- 关于volatile的一些思考C++
在c++中,volatile用与修饰容易变动的变量,通常用于多线程的标志,编译器会存在代码优化,假如在同一个大括号中没有修改这么一个参数,那么编译器很可能在读取这个值的时候使用的是快取的方法,即将这个 ...
- 什么是jquery中的事件委派?
在jquery中有一个很重要的概念——事件委派,相信很多搞前端开发的人都听说过,零度逍遥本来对此不是十分理解,但经过一个高人的指点后,才发现这个功能还是蛮强大的,今天就给大家分享一下. 事件委派的定义 ...
- 转:Redis介绍及常用命令大全
一 Redis介绍 Redis是一个开源的使用ANSI C语言编写.支持网络.可基于内存亦可持久化的日志型.Key-Value数据库,并提供多种语言的API.从2010年3月15日起,Redis的开发 ...
- SVN——Jenkins自动发布
最近公司项目处于开发阶段,很多功能开发完后就需要发布到测试环境等待测试去验收,这个时候如果手动更新网站的话,是很费时费力的. 于是乎,我们做成了自动发布,这样我们只管提交代码到SVN就行了,发布由软件 ...
- Java 系列之Filter(一)
一.过滤器 过滤器就是在源数据和目的数据之间起过滤作用的中间组件.它可以截取客户端和资源之间的请求和响应信息,并且对这些信息进行过滤. 二.应用场景 1.对用户请求进行统一认证 2.对用户的访问请求进 ...