在 DLL 卸载时终止线程

问题描述 投票:0回答:1

我正在尝试为第三方软件编写一个DLL插件。在插件中,我在由托管程序调用的初始化函数中创建一个线程。但是,没有关闭例程可以让我正确终止线程。我尝试过这段代码:

DLL_EXPORT void InitFunction() // is called by the host application
{
    myThread = std::move(std::thread{myThreadFunction});
}
bool WINAPI DllMain( HINSTANCE hDll, DWORD fdwReason, LPVOID lpvReserved )
{
    switch (fdwReason)
    {
    case DLL_PROCESS_ATTACH:
    {
        DisableThreadLibraryCalls(hDll);
    }   break;
    case DLL_PROCESS_DETACH:
    {
        IsRunning.store(false); // tell the thread it's time to terminate;
        if(myThread.joinable())
            myThread.join();
    }break;
    case DLL_THREAD_ATTACH:
        break;
    case DLL_THREAD_DETACH:
        break;
    }
    return true;
}

我知道这行不通,因为Windows会在线程终止时调用DllMain,但DllMain仍在运行,因此会死锁。我尝试在 Dll 的不同位置使用

DisableThreadLibraryCalls()
,但这也不起作用。那么,如何正确终止 DLL 中的线程呢?

c++ multithreading c++11 dll
1个回答
0
投票

rashmatash。

我知道这行不通,因为 Windows 会在线程上调用 DllMain 终止,但 DllMain 仍在运行,因此会 陷入僵局。

这么多实际上是有效的。如果您没有执行DisableThreadLibraryCalls,则所有新生线程都将访问DLL_THREAD_ATTACH 上的DllMain,所有死亡线程将访问DLL_THREAD_DETACH 上的DLL。自从您请求DisableThreadLibraryCalls 以来,没有线程会来访问您的DLL。所以到目前为止我没有看到你的代码有任何僵局。您将获得的唯一访问者是主线程,但仅通过 PROCESS_ATTACH/DETACH。

但是也存在一些问题。 myThread 变量。它是什么?它是 DLL 本地的,对吧?它要么是本地的,要么是从另一个 DLL 导入的,没有 3 种方法。如果它是本地的,则卸载 DLL 将取消 DLL 的代码和数据页的映射,从而导致未定义的行为,可能是访问冲突。所以,我对这个变量不满意。还是可以的。

你可能想做的实际上是一个列表/向量/映射等线程管理结构。您实际上希望线程访问您,因此您可以将它们推送到您的容器中,您希望在它们死亡时删除访问您的线程。您需要保护此容器免受争用。曾经有一段时间,DllMain 访问是序列化的。然后,您可以使用容器中剩余的线程(那些仍然挂起的线程)对 DLL_PROCESS_DETACH 执行某些操作。其中之一是您自己的 InitFunction。

但是,这仍然不对。您应该允许所有访问。您应该记下访问您的第一个线程,顺便说一句,该线程与运行 PROCESS_ATTACH 的线程相同。仅当当前访问线程与记录的 main 匹配时,才将“sigkill”逻辑移至 DLL_THREAD_DETACH。这就像说主线程在退出时应该调用 ShutdownFunction 一样。 DLL 将在每个线程与其分离后处理分离。

此线程/库互锁是保存注册表的 CRT 的一部分。由于您所描述的原因,我们经常必须复制它的某些方面。

© www.soinside.com 2019 - 2024. All rights reserved.