Thread Local Storage

来源:互联网 发布:国际数据分析师认证 编辑:程序博客网 时间:2024/04/27 19:15


Instance(单件)机制原本是让代码执行时只有一个实例,但有的时候又希望每个线程各自能有自己的"单件"相互不影响,处理类似的需求最先想到的就是全局表,然后按线程id或是管理线程的key索引到对应的单件上,取全局表的时候需要加锁。 虽然这样也能实现目的,但是代码看上去很不自然。最近发现还是有更自然的方法能实现这一点,就是 TLS 线程本地存储(Thread Local Storage)

用编译器实现这点比较简单,如果是使用动态创建的方式来实现的单件 则需要申请一个key 来绑定使用这个TLS 单件

---------------------------------------------------------------------------------------------------------------------------

Compiler :

---------------------------------------------------------------------------------------------------------------------------

 _declspec (thread)  InstanceClassA g_ia; 

// 这句告诉给编译器此变量为线程内部使用,每个线程都会copy一份给本地用

---------------------------------------------------------------------------------------------------------------------------


windows 和 linux 下用到的api 稍有不同,但用法差不多,主要是通过申请key 绑定 内存对象 ,释放key 释放内存的 方式进行


WIN API :

---------------------------------------------------------------------------------------------------------------------------

static DWORD InstanceClassA::dwTlsIndex;    

// 定义一些DWORD线程全局变量或函数静态变量,准备作为各个线程访问自己的TLS数组的索引变量

InstanceClassA::dwTlsIndex= TLSAlloc();

 // 当前线程实际上访问的是这个TLS数组索引变量的线程内的拷贝版本。也就说,不同线程虽然看起来用的是同名的TLS数组索引变量,但实际上各个线程得到的可能是不同DWORD值。其意义在于,每个使用TLS的线程获得了一个DWORD类型的线程局部静态变量作为TLS数组的索引变量。C/C++原本没有直接定义线程局部静态变量的机制,所以在如此大费周折

TlsSetValue(InstanceClassA::dwTlsIndex, new InstanceClassA); 

// 动态申请单件内存,然后把指向这块内存区域的指针放入TLS数组相应的槽中,绑定上TlsIndex

InstanceClassA* gp_ia = TlsGetValue(InstanceClassA::dwTlsIndex); 

// 用 TlsIndex 取得单件

delete gp_ia ;  

// 先释放单件内存 

TlsFree(InstanceClassA::dwTlsIndex);

// 然后 释放TLS索引变量  ,如果dwTlsIndex先删除了则很难释放其绑定上的InstanceClassA单件了,在这点上 linux 提供了一个更为保险的方法

----------------------------------------------------------------------------------------------------------------------------

LINUX API :

-----------------------------------------------------------------------------------------------------------------------------

static pthread_key_t InstanceClassA::dwTlsIndex;   

// 这步骤同win 一样

static void InstanceClassA::destroy(void *p) { delete (InstanceClassA*)p; }   

// 为索引提供一个释放绑定对象的方法

pthread_key_create(&InstanceClassA::dwTlsIndex, &InstanceClassA::destroy); 

// 创建出索引并且提供释放方法给索引将会绑定的对象

pthread_setspecific(InstanceClassA::dwTlsIndex, new InstanceClassA); 

// 绑定单件到索引 

InstanceClassA* gp_ia = pthread_getspecific(InstanceClassA::dwTlsIndex); 

// 用 索引 取得单件

pthread_key_delete(InstanceClassA::dwTlsIndex);  

// 释放掉索引的同时 ,也会调用 InstanceClassA::destroy 释放掉InstanceClassA


-----------------------------------------------------------------------------------------------------------------------------

staticInstanceClassA*GetInstance()

{

InstanceClassA* pm = (InstanceClassA*)pthread_getspecific(InstanceClassA::dwTlsIndex);
// or TlsGetValue(InstanceClassA::dwTlsIndex)

if(!pm) pthread_setspecific(InstanceClassA::dwTlsIndex,
pm = new InstanceClassA());  // or
TlsSetValue(InstanceClassA::dwTlsIndex, new InstanceClassA)

return pm;

}

0 0
原创粉丝点击