线程局部存储(TLS)在多线程编程过程中很有用.静态TLS使用方便,但不适合动态链接环境。动态TLS常用的API如下:
DWORD TlsAlloc(void); //查找进程的线程本地存储器的位标志,返回未使用的位标志索引。PS:其返回的索引,在进程的每个线程均保留这个索引
BOOL TlsSetValue( DWORD dwTlsIndex, LPVOID lpTlsValue ); //将一个值放入线程的线程局部存储数组
LPVOID TlsGetValue( DWORD dwTlsIndex); //获取线程指定索引位置的值
BOOL TlsFree( DWORD dwTlsIndex); //释放进程和所有线程指定位置的索引
ACE中对线程局部存储做了封装,封装位于ACE_TSS类.该类是模板类,并重载了->和*操作符,使用起来与智能指针类似.ACE_TSS的使用示例如下:
ACE_TSS<int> data;
void ThreadCall()
{
char szBuffer[1024];
//访问线程局部变量
ACE_OS::sprintf( szBuffer, "当前线程ID: %d ACE_TSS值:%d \n", *data, ACE_Thread::self() );
AtlTrace( szBuffer );
ACE_OS::sleep( 1 );
}
DWORD WorkFunc( void* )
{
//设置线程局部变量为当前线程的ID
*data = ACE_OS::thr_self();
ThreadCall();
return 0;
}
.
//创建10个线程
ACE_Thread_Manager::instance()->spawn_n( 10, (ACE_THR_FUNC)WorkFunc, NULL, THR_NEW_LWP );
//等待所有线程结束
ACE_Thread_Manager::instance()->wait();
使用起来真的很酷,完全隐藏了实现细节.跟踪ACE_TSS的实现源码,简要地分析一下实现过程:
重载的->和*操作符都调用了成员方法ts_get,该方法首先检测是否已经从进程中分配索引,如果没有,则先调用ts_init从进程中分配索引。随后调用ACE_Thread::getspecific获取调用线程某索引处的值,如果还没有值,则调用make_TSS_TYPE分配一个指针值,make_TSS_TYPE也只是简单地调用ACE_NEW_RETURN分配动态对象.分配后调用ACE_Thread::setspecific设置到某索引处.最后值得一提的是清除工作,在析构函数中首先调用ACE_OS::thr_key_detach释放已经分配的内存指针,继而调用ACE_OS::thr_keyfree 释放进程中分配的索引值.