如何在 Windows 上的线程退出时释放 TLS 插槽中的对象? [英] How to release the object in a TLS-slot at thread exit on Windows?

查看:34
本文介绍了如何在 Windows 上的线程退出时释放 TLS 插槽中的对象?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

例如,在多线程程序中:

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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆