多线程程序当中,因为线程之间共享进程的数据,所以在访问全局数据的时候,可能需要加锁互斥访问。但是全局数据的互斥访问只有在多个线程之间协作进行处理的时候,才有必要。但是如果数据在各个线程之间都需要单独的副本,比如说VC CRT库当中的errno变量,我们希望这个变量仅仅由当前线程错误来设置,并且只影响当前线程,那么这种线程之间共享的副本数据该怎么实现呢?
微软提供的一种实现就是TLS(线程局部存储)。TLS有两种实现方法,第一是静态的实现,那就是利用连接器扩展__declspec(thread)修饰所定义的变量,这使得数据在各个线程当中都有副本;另一种方法是利用系统提供的函数动态实现。
首先分析静态实现。在《windows核心编程》里面,作者提到每一个TLS的静态支持需要额外的三条指令。利用实验验证下。
#include<stdio.h>
__declspec(thread) int a;
int main()
{
a=0;
printf("%d",a);
return 0;
}
上面是一个很简单的VC环境下面的程序,利用VC的调试功能对他进行反汇编。得到的汇编代码如下所示:
1: #include<stdio.h>
2: __declspec(thread) int a;
3: int main()
4: {
00401010 push ebp
00401011 mov ebp,esp
00401013 sub esp,40h
00401016 push ebx
00401017 push esi
00401018 push edi
00401019 lea edi,[ebp-40h]
0040101C mov ecx,10h
00401021 mov eax,0CCCCCCCCh
00401026 rep stos dword ptr [edi]
5: a=0;
00401028 mov eax,[__tls_index (00427e58)]
0040102D mov ecx,dword ptr fs:[2Ch]
00401034 mov edx,dword ptr [ecx+eax*4]
00401037 mov dword ptr [edx+104h],0
6: printf("%d",a);
00401041 mov eax,[__tls_index (00427e58)]
00401046 mov ecx,dword ptr fs:[2Ch]
0040104D mov edx,dword ptr [ecx+eax*4]
00401050 mov eax,dword ptr [edx+104h]
00401056 push eax
00401057 push offset string "%d" (0042201c)
0040105C call printf (00401090)
00401061 add esp,8
<