线程私有数据看起来很傻很无聊很没用,但实际上,在某些环境中却是必不可少的一个玩意;C程序
里面其实还是用到大量的全局变量的,但一旦采用全局变量,立即就会和多线程产生很大的冲突;怎么解决
这种冲突呢?第一种是未雨绸缪:为了采用多线程,不采用全局变量;第二种是采用线程私有数据,然后用
宏等手法把线程私有数据包装成全局变量,即既满足了“全局变量”的用法,也能区分不同的线程;初看起来
第一种解决方法是最优的最提倡的,但其实在现实项目中,往往是不太现实的,全局变量既然存在肯定有存在
的理由,比如 errno 这个C一诞生估计就存在的全局变量;历史遗留往往决定了不太可能将全局变量淘汰,另
外在某些情况下,不采用全局变量,将变量传来传去往往也会变得非常讨厌非常恶心;
全局变量有存在的必要性,线程也有其使用的必要性,两者需要兼容的时候,线程私有数据是解决之
道,最优雅的方式是使用者感觉不到全局变量和线程冲突的存在,甚至完全可以达到采用条件编译将其掩盖
起来:在单线程环境中,编译是采用全局变量,多线程中,编译采用的是私有数据;对于使用者来说,他只
需要知道有这样一个 errno 存在即可,他不需要关心这个 errno 到底是全局变量还是一个宏;
在使用线程私有数据的过程中,觉得很多东西都是挺恶心的,定义多个私有数据一直在重复,于是
用宏把这个玩意包装了下:
- #define my_thread_getspecific(func, specific_type, init_done, key, thread_init) \
- static pthread_key_t key; \
- static pthread_once_t init_done = PTHREAD_ONCE_INIT; \
- static void thread_init(void) \
- { \
- pthread_key_create(&key, ::free); \
- } \
- specific_type* func() \
- { \
- specific_type* chk_index_ptr = NULL; \
- pthread_once(&init_done, thread_init); \
- chk_index_ptr = (specific_type*)pthread_getspecific(key); \
- if(chk_index_ptr == NULL) \
- { \
- chk_index_ptr = (specific_type*)malloc(sizeof(specific_type)); \
- assert (chk_index_ptr != NULL); \
- \
- pthread_setspecific(key, chk_index_ptr);\
- } \
- return chk_index_ptr; \
- }
使用起来就不用关心这堆麻烦了,里面包括了线程私有数据的所有细节,重要的就前面两参数:
第一个是函数的名字,第二个是次数据的类型,后面三个参数只要保证名字独立不冲突即可;下面举个简单
的例子说下怎么用,以及配合条件编译实现刚才上面的需求;
头文件中这样定义:
- #ifndef _THREAD_
- extern comm::chk::ChkIndex* __chk_props_;
- #define rc_chk_props __chk_props_
- #else
- extern comm::chk::ChkIndex** __get_chk_index_addr();
- #define rc_chk_props (*__get_chk_index_addr)
- #endif
C文件中这样定义:
- #ifndef _FS_THREAD
- comm::chk::ChkIndex* __chk_props_ = NULL;
- #else
- my_thread_getspecific(__get_chk_index_addr, comm::chk::ChkIndex*, _init, _key, _init_func)
- #endif
阅读(1861) | 评论(0) | 转发(1) |