如何安全地调用 TerminateThread 和 FreeLibrary (WinAPI, C++)

Posted

技术标签:

【中文标题】如何安全地调用 TerminateThread 和 FreeLibrary (WinAPI, C++)【英文标题】:How to safely call TerminateThread and FreeLibrary (WinAPI, C++) 【发布时间】:2020-12-25 21:18:44 【问题描述】:

我曾经通过从使用CreateThread 创建的线程中调用FreeLibraryAndExitThread 来卸载注入的库。

需要从不同的线程卸载库导致这种方法不可能。现在我正在使用TerminateThread(因为它不会终止调用它的线程,而是通过的线程)和FreeLibrary。但是,正如 WinAPI 文档所建议的那样,这会产生“竞争条件”并使进程崩溃。有没有办法解决这个问题?

旧代码:

HMODULE g_hModule NULL ;

BOOL WINAPI DllMain(HMODULE hModule, DWORD fwdReason, LPVOID lpReserved) 
    g_hModule = hModule;
    if (fwdReason == DLL_PROCESS_ATTACH) 
        DisableThreadLibraryCalls(hModule);
        CreateThread(0, 0, (LPTHREAD_START_ROUTINE)main, 0, 0, 0);
    

    return TRUE;


void Unload(int nExitCode) 
    FreeLibraryAndExitThread(g_hModule, (DWORD)nExitCode);

新代码:

HMODULE g_hModule NULL ;
HANDLE g_hThread NULL ;

BOOL WINAPI DllMain(HMODULE hModule, DWORD fwdReason, LPVOID lpReserved) 
    g_hModule = hModule;
    if (fwdReason == DLL_PROCESS_ATTACH) 
        DisableThreadLibraryCalls(hModule);
        g_hThread = CreateThread(0, 0, (LPTHREAD_START_ROUTINE)main, 0, 0, 0);
    

    return TRUE;


void Unload(int nExitCode) 
    TerminateThread(g_hThread, (DWORD)nExitCode);
    FreeLibrary(g_hModule);

提前感谢您的帮助!

【问题讨论】:

这能回答你的问题吗? Kill a running thread 无论如何,在这里搜索“[c++] 终止线程”,你会发现很多信息。在进一步探索这条道路之前,了解终止线程的含义。 简短回答:不,没有。 C++ 不能以这种方式工作。除了从原始线程函数返回之外,通过任何方式终止线程都是未定义的行为。 TerminateThread 没有明确定义的 C++ 代码行为。它不适用于 C++ 代码。 新代码在所有情况下都是错误的并且毫无意义。 TerminateThread - 你终止了 self 线程。 FreeLibrary 永远不会被调用。没有意义创建线程只是为了终止它(甚至不正确退出)。旧代码看起来是正确的(假设 main == Unload 和错误的卸载签名) 在旧代码中Unload 是从main(由CreateThread 创建的线程)调用的,而在新代码中它是从一个单独的线程调用的。这就是为什么我认为 FreeLibrary 应该运行 ULONG WINAPI Unload(PVOID) FreeLibraryAndExitThread((HMODULE)&__ImageBase, 0);CreateThread(0, 0, Unload, 0, 0, 0); 这就是代码需要的样子 【参考方案1】:

安全终止线程的唯一方法,尤其是在 C++ 中,是让该线程从传递给 CreateThread 的函数返回。这通常通过设置(比如)一个atomic<bool> 来完成,该线程定期测试以查看它是否应该退出。您还可以使用条件变量(或 Win32 等效项)来唤醒线程,而不是忙循环。

TerminateThread 非常危险,例如,线程可能当时持有某种关键锁(可能是malloc 使用的锁),这会挂起您的应用程序的其余部分。它本来就不应该在 Win32 API 中提供,你不应该使用它。

【讨论】:

但是TerminateThread 与问题有何关联?关于如何从这个 dll 中取消引用 dll 的问题。 OP 想要卸载 dll。绝对与终止线程无关

以上是关于如何安全地调用 TerminateThread 和 FreeLibrary (WinAPI, C++)的主要内容,如果未能解决你的问题,请参考以下文章

获取/检查进程 win32 的内部 kernel32 状态(为了安全使用 TerminateThread )

delphi TerminateThread 结束一个线程后内存残留

在 C++ 代码中调用 TerminateThread 后在 C# 代码中检测到 FatalExecutionEngineError

TerminateThread 可以终止另一个进程的线程吗?

线程天敌TerminateThread与SuspendThread

如何安全地测试一个方法是不是可以通过 NSInvocation 被调用