windows线程局部存储(TLS)原理解析

动态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

发布了140 篇原创文章 · 获赞 65 · 访问量 1万+

猜你喜欢

转载自blog.csdn.net/paradox_1_0/article/details/103375961