如何在 Windows 上的线程退出时释放 TLS 插槽中的对象? [英] How to release the object in a TLS-slot at thread exit on Windows?
问题描述
例如,在多线程程序中:
for example, in a multi-thread program:
struct TLSObject;
void foo()
{
TLSObject* p = TlsGetValue(slot);
if (p == 0) {
p = new TLSObject;
TlsSetValue(slot, p);
}
// doing something with p
}
在任何线程中第一次调用 foo() 都会创建一个新的 TLSObject.
the first time to call foo() in any thread will makes a new TLSObject.
我的问题是:如何删除 TLSObject(如果我不使用 boost::thread 和 boost::thread_specific_ptr)?
my question is: How to delete a TLSObject(if I don't use boost::thread and boost::thread_specific_ptr) ?
boost::thread_specific_ptr 可以在线程退出时做清理工作,但这取决于 boost::thread 我猜,不适用于普通的操作系统线程,而且速度很慢.
boost::thread_specific_ptr can do cleanup work at thread exit, but it depends on boost::thread I guess, not for normal OS thread, and it's slow.
推荐答案
好的.对于 Windows Vista 及更高版本,正如 James McNellis 所说 - 我们可以使用 FlsCallback.
Alright. For Windows Vista and above, as James McNellis said - we could use FlsCallback.
对于一个 DLL,我们可以只使用 DllMain,如果原因参数等于到 DLL_THREAD_DETACH,我们进行清理.另一种选择可能是使用_pRawDllMain,它就像另一个DllMain,你可以从 boost 源 中找到.
For a DLL, we could just use DllMain, if reason parameter equals to DLL_THREAD_DETACH, we do the cleanup. An alternative might be to use _pRawDllMain, it's just like another DllMain, you could find it from boost source.
对于 EXE,我们可以使用 TLS 回调,请查看此处 和 这里,当然还有 增强源.在实践,它适用于 Windows XP,但我发现优化可能会使其无效,所以要小心优化,或者使对回调函数指针的显式引用.
For an EXE, we could use TLS callback, please have a look at here and here, and, of course, boost source. In practice, it works on Windows XP, but I found that optimizations may make it ineffective, so be careful with optimizations, or make a explicit reference to the pointer of your callback function.
将下面的代码保存到 tls.cpp 并添加到你的项目中,不不管是 exe 还是 dll,它都会工作.请注意,对于 DLLWindows Vista 及以上的 onThreadExit 函数可能会被调用两次 - 一次来自 dll_callback,一次来自 tls_callback.
Save the code below to tls.cpp and add it to your project, no matter it's exe or dll, it will work. Note that for a DLL on Windows Vista and above the onThreadExit function may be called twice - one from dll_callback and one from tls_callback.
#include <windows.h>
extern void onThreadExit();
static void NTAPI tls_callback(PVOID, DWORD reason, PVOID)
{
if (reason == DLL_THREAD_DETACH) {
onThreadExit();
}
}
static BOOL WINAPI dll_callback(LPVOID, DWORD reason, LPVOID)
{
if (reason == DLL_THREAD_DETACH) {
onThreadExit();
}
return TRUE;
}
#pragma section(".CRT$XLY",long,read)
extern "C" __declspec(allocate(".CRT$XLY")) PIMAGE_TLS_CALLBACK _xl_y = tls_callback;
extern "C"
{
extern BOOL (WINAPI * const _pRawDllMain)(HANDLE, DWORD, LPVOID) = &dll_callback;
}
#pragma comment(linker, "/INCLUDE:__tls_used")
#pragma comment(linker, "/INCLUDE:__xl_y")
如果你觉得它晦涩难懂,请使用boost的at_thread_exit,复杂性是隐藏的.实际上上面的代码是一个简化的升压 tls 的版本.如果你不想使用 boost,在Windows 系统这是一个替代方案.
If you think it's obscure, use boost's at_thread_exit, the complexity is hidden. In fact the code above is a simplified version of boost tls. And if you do not want to use boost, on Windows system this is a alternative.
或者,更通用的方法:thread_local.
Or, a more generic way: thread_local.
这篇关于如何在 Windows 上的线程退出时释放 TLS 插槽中的对象?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!