我在 MSDN 中发现了关于线程本地存储的初始值的矛盾。 这个页面说:
创建线程时,系统会为 TLS 分配一个 LPVOID 值数组,这些值初始化为 NULL。
这让我相信,如果我从一个从未为同一索引调用过 TlsSetValue 的线程中使用有效索引调用 TlsGetValue,那么我应该得到一个空指针。
但是,此页面说:
程序员有责任确保……线程在调用 TlsGetValue 之前调用 TlsSetValue。
这表明您不能依赖从 TlsGetValue 返回的值,除非您确定它已使用 TlsSetValue 显式初始化。
然而,第二页同时通过以下内容强化了初始化为空的行为:
存储在 TLS 槽中的数据可以具有值 0,因为它仍然具有其初始值,或者因为线程调用 TlsSetValue 函数时使用 0。
所以我有两条语句说数据被初始化为 null(或 0),还有一条语句说我必须在读取值之前显式初始化它。实验上,这些值似乎确实被自动初始化为空指针,但我无法知道我是否只是幸运,以及是否总是如此。
我试图避免使用 DLL 来分配 DLL_THREAD_ATTACH。我想按照以下方式进行惰性分配:
LPVOID pMyData = ::TlsGetValue(g_index);
if (pMyData == nullptr) {
pMyData = /* some allocation and initialization*/;
// bail out if allocation or initialization failed
::TlsSetValue(g_index, pMyData);
}
DoSomethingWith(pMyData);
这是一种可靠且安全的模式吗?或者我是否必须在尝试读取之前明确初始化每个线程中的插槽?
更新:文档还说TlsAlloc 将已分配索引的插槽归零。因此,程序的另一部分以前是否使用过插槽似乎无关紧要。