Chinaunix首页 | 论坛 | 博客
  • 博客访问: 519940
  • 博文数量: 78
  • 博客积分: 995
  • 博客等级: 准尉
  • 技术积分: 1462
  • 用 户 组: 普通用户
  • 注册时间: 2011-11-15 20:22
个人简介

技术中沉思的时候最快乐,问题得到完美解决的时候最有成就感!

文章分类

全部博文(78)

文章存档

2013年(39)

2012年(37)

2011年(2)

分类: C/C++

2012-10-30 15:22:35

线程私有数据看起来很傻很无聊很没用,但实际上,在某些环境中却是必不可少的一个玩意;C程序
里面其实还是用到大量的全局变量的,但一旦采用全局变量,立即就会和多线程产生很大的冲突;怎么解决
这种冲突呢?第一种是未雨绸缪:为了采用多线程,不采用全局变量;第二种是采用线程私有数据,然后用
宏等手法把线程私有数据包装成全局变量,即既满足了“全局变量”的用法,也能区分不同的线程;初看起来
第一种解决方法是最优的最提倡的,但其实在现实项目中,往往是不太现实的,全局变量既然存在肯定有存在
的理由,比如 errno 这个C一诞生估计就存在的全局变量;历史遗留往往决定了不太可能将全局变量淘汰,另
外在某些情况下,不采用全局变量,将变量传来传去往往也会变得非常讨厌非常恶心;

全局变量有存在的必要性,线程也有其使用的必要性,两者需要兼容的时候,线程私有数据是解决之
道,最优雅的方式是使用者感觉不到全局变量和线程冲突的存在,甚至完全可以达到采用条件编译将其掩盖
起来:在单线程环境中,编译是采用全局变量,多线程中,编译采用的是私有数据;对于使用者来说,他只
需要知道有这样一个 errno 存在即可,他不需要关心这个 errno 到底是全局变量还是一个宏;

在使用线程私有数据的过程中,觉得很多东西都是挺恶心的,定义多个私有数据一直在重复,于是
用宏把这个玩意包装了下:

点击(此处)折叠或打开

  1. #define my_thread_getspecific(func, specific_type, init_done, key, thread_init) \
  2. static pthread_key_t key; \
  3. static pthread_once_t init_done = PTHREAD_ONCE_INIT; \
  4. static void thread_init(void) \
  5. { \
  6.         pthread_key_create(&key, ::free); \
  7. } \
  8. specific_type* func() \
  9. { \
  10.         specific_type* chk_index_ptr = NULL; \
  11.         pthread_once(&init_done, thread_init); \
  12.         chk_index_ptr = (specific_type*)pthread_getspecific(key); \
  13.         if(chk_index_ptr == NULL) \
  14.         { \
  15.                 chk_index_ptr = (specific_type*)malloc(sizeof(specific_type)); \
  16.                 assert (chk_index_ptr != NULL); \
  17.                 \
  18.                 pthread_setspecific(key, chk_index_ptr);\
  19.         } \
  20.         return chk_index_ptr; \
  21. }

使用起来就不用关心这堆麻烦了,里面包括了线程私有数据的所有细节,重要的就前面两参数:
第一个是函数的名字,第二个是次数据的类型,后面三个参数只要保证名字独立不冲突即可;下面举个简单
的例子说下怎么用,以及配合条件编译实现刚才上面的需求;

头文件中这样定义:

点击(此处)折叠或打开

  1. #ifndef _THREAD_
  2. extern comm::chk::ChkIndex* __chk_props_;
  3. #define rc_chk_props __chk_props_
  4. #else
  5. extern comm::chk::ChkIndex** __get_chk_index_addr();
  6. #define rc_chk_props (*__get_chk_index_addr)
  7. #endif

C文件中这样定义:

点击(此处)折叠或打开

  1. #ifndef _FS_THREAD
  2. comm::chk::ChkIndex* __chk_props_ = NULL;
  3. #else
  4. my_thread_getspecific(__get_chk_index_addr, comm::chk::ChkIndex*, _init, _key, _init_func)
  5. #endif


阅读(1861) | 评论(0) | 转发(1) |
给主人留下些什么吧!~~