线程特定数据

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));

在单线程程序中,我们经常要用到"全局变量"以实现多个函数间共享数据, 然而在多线程环境下,由于数据空间是共享的,因此全局变量也为所有线程所共有。但有时应用程序设计中有必要提供线程私有的全局变量,仅在某个线程中有效,但却可以跨多个函数访问。POSIX线程库通过维护一定的数据结构来解决这个问题,这个些数据称为(Thread-specific-data或 TSD), 线程特定数据如下图所示:

从上图可知:当调用pthread_key_create 后会产生一个所有线程都可见的线程特定数据(TSD)的键值(如上图中所有的线程都会得到一个pkey[1]的值), 但是这个键所指向的真实数据却是不同的,虽然都是pkey[1], 但是他们并不是指向同一块内存,而是指向了只属于自己的实际数据, 因此, 如果线程0更改了pkey[1]所指向的数据, 而并不能够影像到线程n;

在线程调用pthread_setspecific后会将每个线程的特定数据与thread_key_t绑定起来,虽然只有一个pthread_key_t,但每个线程的特定数据是独立的内存空间,当线程退出时会执行destructor 函数。

/** 示例1: 设置/获取线程特定数据
在两个线程中分别设置/获取线程特定数据, 查看两个线程中的数据是否是一样的(肯定是不一样的O(∩_∩)O~)
**/
pthread_key_t key;
typedef struct Tsd
{pthread_t tid;char *str;
} tsd_t;
//用来销毁每个线程所指向的实际数据
void destructor_function(void *value)
{free(value);cout << "destructor ..." << endl;
}void *thread_routine(void *args)
{//设置线程特定数据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()
{//这样每个线程当中都会有一个key可用了,//但是每个key所绑定的实际区域需要每个线程自己指定pthread_key_create(&key, destructor_function);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;
}
/** 示例2:运用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;
}

附-Linux/Unix线程私有数据实现思想:

原文连接:http://blog.csdn.net/caigen1988/article/details/7901248

线程私有数据实现的主要思想是:在分配线程私有数据之前,创建与该数据相关联的键,这个键可以被进程中的所有线程使用,但每个线程把这个键与不同的线程私有数据地址进行关联,需要说明的是每个系统支持有限数量的线程特定数据元素(如:限制为128个)。那么这个键的实现原理是什么呢?

其实系统为每个进程维护了一个称之为 Key 结构的结构数组,如下图所示:

(图1)

在上图中Key 结构的“标志”指示这个数据元素是否正在使用。在刚开始时所有的标志初始化为“不在使用”。当一个线程调用pthread_key_create创建一个新的线程特定数据元素时,系统会搜索Key结构数组,找出第一个“不在使用”的元素。并把该元素的索引(0~127,称为“键”)返回给调用线程。

除了进程范围内的Key结构数组之外,系统还在进程内维护了关于多个线程的多条信息。这些特定于线程的信息我们称之为pthread结构。其中部分内容是我们称之为pkey数组的一个128个元素的指针数组。系统维护的关于每个线程的信息结构图如下:

(图2)

在上图中,pkey数组所有元素都被初始化为空指针。这些128个指针是和进程内128个可能的键逐一关联的值。

那么当我们调用pthread_key_create函数时,系统会为我们做什么呢?

系统首先会返回给我们一个Key结构数组中第一个“未被使用”的键(即索引值),每个线程可以随后通过该键找到对应的位置,并且为这个位置存储一个值(指针)。 一般来说,这个指针通常是每个线程通过调用malloc来获得的。

知道了大概的私有数据实现的原理,那么在编程中如何使用线程的特定数据呢?

假设一个进程被启动,并且多个线程被创建。 其中一个线程调用pthread_key_create。系统在Key结构数组(图1)中找到第1个未使用的元素。并把它的索引(0~127)返回给调用者。我们假设找到的索引为1。

之后线程调用pthread_getspecific获取本线程的pkey[1] 的值(图(2)中键1所值的指针), 返回值是一个空值,线程那么调用malloc分配内存区并初始化此内存区。 之后线程调用pthread_setspecific把对应的所创建键的线程特定数据指针(pkey[1]) 设置为指向它刚刚分配的内存区。下图指出了此时的情形。

(图3)

明白了怎样获取线程的特定数据值,那么如果线程终止时系统会执行什么操作呢?

我们知道,一个线程调用pthread_key_create创建某个特定的数据元素时,所指定的参数之一便是指向析构函数的指针。当一个线程终止时,系统将扫描该线程的pkey数组,为每个非空的pkey指针调用相应的析构函数。 相应的析构函数是存放在图1中的Key数组中的函数指针。这是一个线程终止时其线程特定数据的释放手段。

Linux多线程实践(4) --线程特定数据相关推荐

  1. Linux多线程实践(1) --线程理论

    线程概念 在一个程序里的一个执行路线就叫做线程(thread).更准确的定义是:线程是"一个进程内部的控制序列/指令序列"; 一切进程至少有一个执行线程; 进程  VS. 线程  ...

  2. Linux多线程实践(2) --线程基本API

    POSIX线程库 与线程有关的函数构成了一个完整的系列,绝大多数函数的名字都是以"pthread_"开头,要使用这些函数库,要通过引入头文<pthread.h>,而且链 ...

  3. Linux多线程实践(3) --线程属性

    初始化/销毁线程属性 int pthread_attr_init(pthread_attr_t *attr); int pthread_attr_destroy(pthread_attr_t *att ...

  4. Linux多线程实践(四 )线程的特定数据

    在单线程程序中.我们常常要用到"全局变量"以实现多个函数间共享数据, 然而在多线程环境下.因为数据空间是共享的.因此全局变量也为全部线程所共同拥有.但有时应用程序设计中有必要提供线 ...

  5. Linux多线程实践(10) --使用 C++11 编写 Linux 多线程程序

    在这个多核时代,如何充分利用每个 CPU 内核是一个绕不开的话题,从需要为成千上万的用户同时提供服务的服务端应用程序,到需要同时打开十几个页面,每个页面都有几十上百个链接的 web 浏览器应用程序,从 ...

  6. Linux多线程实践(二)线程基本API(POSIX)

    我们知道,进程在各自独立的地址空间中运行,进程之间共享数据需要用进程间通信机制,有些情况需要在一个进程中同时执行多个控制流程,这时候线程就派上了用场,比如实现一个图形界面的下载软件,一方面需要和用户交 ...

  7. 【Linux系统编程】线程私有数据

    00. 目录 文章目录 00. 目录 01. 线程之间共享数据 02. 线程私有数据 2.1 创建线程私有数据 2.2 销毁线程私有数据 2.3 关联线程私有数据成员 2.4 读取线程私有数据所关联的 ...

  8. Linux多线程实践(一)线程基本概念和理论

    线程概念 在一个程序里的一个运行路线就叫做线程(thread).更准确的定义是:线程是"一个进程内部的控制序列/指令序列"; 对于每一个进程至少有一个运行线程; 进程  VS. 线 ...

  9. Linux多线程实践(9) --简单线程池的设计与实现

    线程池的技术背景 在面向对象编程中,创建和销毁对象是很费时间的,因为创建一个对象要获取内存资源或者其它更多资源.在Java中更是如此,虚拟机将试图跟踪每一个对象,以便能够在对象销毁后进行垃圾回收.所以 ...

最新文章

  1. yum安装mysql步骤及报错ERROR 1045 (28000)
  2. python学精通要多久-学Python编程难吗 从入门到精通学习Python要多久
  3. 五一假期将至,机房维护工作要做好
  4. webpack 独立打包 css 文件
  5. 《Python Cookbook 3rd》笔记(4.9):排列组合的迭代
  6. 手把手教你用Scrapy爬取知乎大V粉丝列表
  7. 呆错网址导航系统V1.13.18 PHP源码
  8. 用足球阵型告诉你,阿里云如何护航全网70%世界杯流量
  9. FusionCharts 分类以及各个属性参数列表
  10. matlab中idwt,matlab图片处理
  11. 算法:线性时间选择(C/C++)
  12. fpga与海思BT1120调试问题记录
  13. 最好用的切图工具——firework
  14. 2021年南京市高考成绩查询,2021年南京高考各高中成绩及本科升学率数据排名及分析...
  15. bzoj 2429 聪明的猴子
  16. job用法 Java_JOB 用法小结
  17. 关于整合ssh的问题,新人求关照
  18. 查询网站排名,收录情况
  19. 失落的时候如何调整自己的心情
  20. 使用与破解ExcelVBA密码

热门文章

  1. 计组之存储系统:1、存储系统的概念与基本组成(层次、分类、性能指标、基本结构、寻址)
  2. 2-2:套接字(Socket)编程之深入了解套接字
  3. Python解析xml文件,此实例将xml设置为模版(from lxml import etree)
  4. SQLAlchemy ORM教程之二:Query
  5. 如何在虚拟机中安装kali linux
  6. Linux系统编程:获取指定目录下指定文件类型的数量
  7. 设计模式-结构型模式-装饰模式
  8. JS对以对象组成的数组去重
  9. matconvnet在ubuntu15.10下配置和使用方法
  10. 提高tomcat的并发能力