动态TLS
windows系统中每个进程都有一组正在使用标志(in-use-flag),如图21-1所示。每个标志可以被设为FREE或着INUSE,表示改TLS元素是否正在被使用。Microsoft保证至少有TLS_MINIMUM_AVAILABLE = 64个位标志可供使用。在必要的时候可以配更多,最多可达1000多个!
要使用动态TLS,我们必须先调用TlsAlloc:
DWORD TlsAlloc();
这个函数让系统对进程中的位标志进行检索并找到一个FREE标志。接着系统会将FREE——>INUSE并让TlsAlloc返回该标志在数组中的索引。一个DLL(或应用程序)通常将这个索引保存在一个全局变量中。由于这个值会在整个进程范围内使用,而不是在线程范围内使用,因此这种情况下全局变量是一个很好的选择。
如果TlsAlloc没有找到FREE标志,会返回TLS_OUT_OF_INDEXES(WinBases.h中被定义为0xFFFFFFFF)。
接下来这一步是关键,也就是所谓的"线程局部"的关键:
当系统创建一个线程时,会分配TLS_MINIMUM_AVAILABLE个PVOID值,将他们都初始化为0,并与线程关联起来。每个线程都有自己的PVOID数组,数组中每个PVOID可以保存任意值。
为了把一个值保存到线程的PVOID数组中,需要调用TlsSetValue函数:
BOOL TlsSetValue(DWORD dwTlsIndex, PVOID pvTlsValue);
这个函数把pvTlsValue参数标识的PVOID值放到线程的数组中,参数dwTlsIndex标识一个索引值,表示索引中的具体位置。pvTlsValue值会与TlsSetValue的调用线程关联起来。如果调用成功,那么TlsSetValue函数或返回TRUE。当一个线程调用TlsSetValue的时候,会修改自己的数组。
为了是这些函数运行的快,微软在实现他们的时候牺牲了错误检查。
为了从线程的数组中取回一个值,我们应该调用TlsGetValue:
PVOID TlsGetValue(DWORD dwTlsIndex);
这个函数会返回在索引为dwTlsIndex的TLS元素返回的值。
当我们不再需要一个已经预定的TLS元素时,应该调用TlsFree:
BOOL TlsFree(DWORD dwTlsIndex);
参考:https://www.cnblogs.com/hdtianfu/archive/2012/10/18/2730282.html