linux下线程局部存储,10.5.2 线程相关的数据/线程局部存储

10.5.2  线程相关的数据/线程局部存储

PTHREADS和Win32线程基础设施都提供了某种程度上的TSS。PTHREADS[Bute1997]中的版本称为线程相关数据(TSD,Thread-Specific Data),Win32上的版本则被称为线程局部存储(TLS,Thread-Local Storage),它们的意思是一样的。

它们都提供某种方式来创建这样一个变量,该变量在进程中的每个使用它的线程中都具有不同的值。在PTHREADS里,该值被称为键(key),而在Win32上则被称为索引(index)。Win32把用于存放各线程中的键值的内存位置称为槽位(slot)。我喜欢键、槽位和值这3种说法。

PTHREADS的TSD基于如下的4个库函数:int pthread_key_create(    pthread_key_t  *key

,    void (*destructor)(void *));

int pthread_key_delete(    pthread_key_t  key);

void *pthread_getspecific( pthread_key_t  key);

int pthread_setspecific(   pthread_key_t  key

,   const void     *value);

pthread_key_create()创建了pthread_key_t类型的一个键(不透明类型)。调用者还可以传递一个清理函数,待会我们会讨论这个函数。通过调用pthread_setspecific()和pthread_getspecific()可以线程相关地设置或获取值。pthread_key_delete()则被用来销毁不再被需要的键。

Win32的TLS API具有类似的"四大金刚":DWORD  TlsAlloc(void);

LPVOID TlsGetValue(DWORD dwTlsIndex);

BOOL   TlsSetValue(DWORD dwTlsIndex, LPVOID lpTlsValue);

BOOL   TlsFree(DWORD dwTlsIndex);

这些TSS API的常规用法是这样的:在主线程中,在任何其他线程活动之前,创建一个键,并将该键保存在一个公共地点(全局变量,或者通过某个函数返回),然后所有线程就可以通过从它们各自的槽位中存入或获取值,来操纵它们各自的TSS数据的拷贝。

遗憾的是,在这些模型中存在着若干不足,尤其是Win32的版本。

首先,这些API所能提供的键的数目有限。PTHREADS保证至少有128个,Win32则是64个。1尽管实际上人们很少会超过这个限度,但考虑到软件的多组件特征日益明显,要求更多键的可能性并非一点都没有。

第二个问题是Win32 API并没有提供任何在线程退出时清理槽位的能力。这意味着人们某种程度上必须能够拦截线程的退出,并借机清理与该线程的槽位中的值相关的资源。当然,对于C++用户而言,语言本身提供了自动析构机制,可以使我们免受这方面的痛苦,而且在某些场合非这种方式不能如愿。

尽管PTHREADS提供了在线程终止时清理资源的手段,但是它仍然没有提供完整的简单正确的资源处理机制。从本质上说,PTHREADS提供了常性(immutable)RAII(见3.5.1小节)。尽管这相对于Win32缺乏任何RAII是一个极大的改进,但有时候确实需要改变给定键对应的槽位值的能力。手工清理原先的值也是可行的,但是如果这种能力是自动的话要好得多。

第四个问题是,PTHREADS假定清理函数在清理点是可调用的。如果在某个线程退出时,它的清理函数将要(直接或间接)调用的API已经被反初始化(uninitialized)了,那么对该清理函数的调用就可能是无效的。类似的一个情况,甚至可算是实践中更常见的情况是,如果清理函数是位于动态库中的,那么此时该清理函数可能已经不再存在于进程的地址空间中了,而这则意味着进程崩溃。

【责任编辑:book TEL:(010)68476606】

点赞 0

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值