条目1、使用线程局部存储区(Thread Local Storage)可以讲数据和一个指定的线程关联起来。(P565)
条目2、由于早期运行库中的大多数函数设计在单线程的基础上,为保证在多线程的情况下这些函数(特别是使用了静态变量/全局变量的函数)的行为不发生改变,C/C++运行库使用了TLS。(p565)
条目3、TLS技术分为:动态TLS和静态TLS。(P566)
条目4、动态TLS应用的四个函数:TlsAlloc、TlsSetValue、TlsGetValue、TlsFree。
TlsAlloc函数检索进程内的位标志为FREE的索引,把该索引的标志位INUSE、内容清零并返回。该索引对进程内的所有线程或以后新建的线程而言,都是处在可直接使用的状态。换句话说,线程1调用TlsAlloc返回索引3,那么其他线程再怎么调用TlsAlloc,也不会返回索引3。(P567)
TlsSetValue函数修改当前线程的TLS值,不会影响到其他线程。为了提升性能,系统不对TlsSetValue函数中的索引做错误检查。(P568)
TlsGetValue函数获取当前线程的TLS值。
TlsFree函数释放进程内已经预定的TLS索引,将其状态更改为FREE。
动态TLS示例:
DWORD g_dwTlsIndex = -1;
unsigned TlsProc1(void *unuse)
{
LPVOID lpValue = NULL;
TlsSetValue(g_dwTlsIndex,(PVOID)1234);//2
Sleep(1000);
lpValue = TlsGetValue(g_dwTlsIndex); //5
printf("TlsProc1:%d/n",(DWORD)lpValue);
return 0;
}
unsigned TlsProc2(void *unuse)
{
LPVOID lpValue = NULL;
TlsSetValue(g_dwTlsIndex,(PVOID)4567);//3
lpValue = TlsGetValue(g_dwTlsIndex); //4
printf("TlsProc2:%d/n",(DWORD)lpValue);
return 0;
}
int main(void)
{
g_dwTlsIndex = TlsAlloc(); // 1
_beginthreadex(NULL,0,TlsProc1,NULL,0,NULL);
_beginthreadex(NULL,0,TlsProc2,NULL,0,NULL);
_getch();
}
条目5、静态TLS使用__declspec(thread)修饰符声明全局或静态(static)的TLS变量,TLS变量将被编译器放到.tls段中。
系统在载入应用程序时,将根据.tls段的大小分配足够的内存来保存所有的静态TLS变量。若进程新建了一个线程,那么系统也要为新线程分配一样大的内存来保存的静态TLS变量。如果在加载一个DLL时,DLL中也存在静态TLS变量,那么系统会为进程中的所有线程扩展其TLS的内存容量。如果卸载一个DLL时,DLL中存在静态TLS变量,那么系统会为进程中的所有线程缩减其TLS的内存容量。(P571)
静态TLS示例:
__declspec(thread) DWORD g_dwTlsValue = 0;
unsigned TlsProc1(void *unuse)
{
g_dwTlsValue = 0x12345678; // 1
Sleep(1000);
printf("TlsProc1:0x%08x/n",g_dwTlsValue); //4
return 0;
}
unsigned TlsProc2(void *unuse)
{
g_dwTlsValue = 0x87654321; //2
printf("TlsProc2:0x%08x/n",g_dwTlsValue);//3
return 0;
}
int main(void)
{
_beginthreadex(NULL,0,TlsProc1,NULL,0,NULL);
_beginthreadex(NULL,0,TlsProc2,NULL,0,NULL);
_getch();
}