线程私有数据(Thread-Specific Data)

 

线程私有数据存在的原因在于有时需要维护基于每个线程的数据,通俗来说就是有些数据

在每个线程中都存在,各个线程都应该拥有自己的私有版本,改动自己的数据不应弄乱别人

的,假若这些数据是全局的,也就是说不能分配在线程栈中,那怎么办?数据的名称可是一样

的哦.如果简单地声明一个全局变量,则这个全局变量会被其他线程所共享.

从数据结构的观点看,这里的要求是每个线程都从同一个名称出发,但能访问到不同的数据

,这种类型的数据,很遗憾,不存在.只有通过操作,也就是函数去实现了.

想想我们能提供什么去获取这个数据吧:线程ID, 数据名称.我首先想到的是使用hash函数

,但处理冲突好像很麻烦,这大概就是pthread实现采用键并限制线程私有数据数量的原因

吧,细节就不管了.

 

具体操作线程私有数据的函数有:

int pthread_key_create(pthread_key_t *keyp,

             void (* destructor )(void *));

每份私有数据对应着一个keyp,destructor用于线程退出时清理私有数据(明显,私有数据

不是分配在线程栈上,而是进程堆中).

 

int pthread_key_delete(pthread_key_t *key);

用于删除key,但好像没什么用.注意它不会调用destructor,所以要主动清理.

 

明显,每个线程对每一份私有数据拥有的key应该是一样的,所以不能让多个线程对同一个

key调用pthread_key_create().解决方法是使用pthread_once():

int pthread_once(pthread_once_t *initflag, void

     (*initfn)(void));

initflag要求是非本地变量(例如全局,静态变量),并被初始化为PTHREAD_ONCE_INIT.

如果每个线程都调用pthread_once()以产生key,系统保证只在第一次调用pthread_once()

时调用initfn.

APUE建议使用下面的序列:

void destructor(void *);

pthread_key_t key;

pthread_once_t init_done = PTHREAD_ONCE_INIT;

void

thread_init(void)

{

   err = pthread_key_create(&key, destructor);

}

int

threadfunc(void *arg)

{

   pthread_once(&init_done, thread_init);

   ...

}

那为什么不直接在线程产生之前在主线程调用pthread_create_key()呢?原因是这会暴露

太多细节,试想私有数据是某个库函数的,主线程又如何得知它使用的key是什么呢?而如果

库函数要求主线程在生成其它线程之前就调用某个初始化函数,是不是太什么了一点?如果

说一个库函数调用还可以接受的话,那么大量的库函数调用呢?

 

当一个key产生之后,我们可以调用pthread_setspecific为这个key关线程私有数据,调用

pthread_getspecific去获取:

int pthread_setspecific(pthread_key_t key, const void *value);

void *pthread_getspecific(pthread_key_t key);

 

 

以下是APUE利用线程私有数据实现的线程安全getenv:

 

 

注意ARG_MAX不知道是在哪里定义的,自己定义一个就好,但一定要注意足够大,否则线程结束时free会出错.

以下是调用该函数的主函数,其中error.h在apue里提供的源码里可能也有吧,我是从unix网络编程(同一个作者)里拿来的:

 

 

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值