c++ - 如何在 dll (c++) 中创建线程?

标签 c++ windows multithreading dll

我知道我不能从 DllMain 创建线程,但是在 DLL 中创建线程的正确方法是什么?

我试图创建一个环绕它的类并声明该类的一个全局实例,但是 WaitForSingleObject 卡在该类的析构函数中,即使我确定线程已经退出。

这是我从 exe 加载 dll 的示例程序:

#include <Windows.h>
#include <iostream>

using namespace std;

int main(int argc, TCHAR* argv[])
{
    HMODULE module = LoadLibraryA("dll.dll");
    Sleep(500);
    if (module) FreeModule(module);
    else cout << "failed to load library...\n";
    return 0;
}

这里是dll代码:

#include <Windows.h>
#include <iostream>

using namespace std;

class X
{
    HANDLE thread = NULL;

    static DWORD WINAPI run_thread(LPVOID param)
    {
        cout << "dll.cpp: thread started\n";
        Sleep(1000);
        cout << "dll.cpp: thread is exiting\n";
        return 0;
    }

public:
    X()
    {
        DWORD tmp;
        thread = CreateThread(NULL, 0, run_thread, NULL, 0, &tmp);
        if (thread == NULL)
        {
            cout << "failed to create thread\n";
            throw 1;
        }
    }
    ~X()
    {
        if (thread != NULL)
        {
            cout << "joining thread...\n";
            DWORD ret = WaitForSingleObject(thread, INFINITE);
            cout << "result from waiting: " << ret << "\n";
            thread = NULL;
        }
    }
}x;

BOOL APIENTRY DllMain(HMODULE hModule, DWORD reason, LPVOID lpReserved)
{
    switch (reason)
    {
    case DLL_PROCESS_ATTACH:
        cout << __FUNCTION__ << " reason DLL_PROCESS_ATTACH\n";
        break;
    case DLL_THREAD_ATTACH:
        cout << __FUNCTION__ << " reason DLL_THREAD_ATTACH\n"; 
        break;
    case DLL_THREAD_DETACH:
        cout << __FUNCTION__ << " reason DLL_THREAD_DETACH\n"; 
        break;
    case DLL_PROCESS_DETACH:
        cout << __FUNCTION__ << " reason DLL_PROCESS_DETACH\n"; 
        break;
    }

    return TRUE;
}

这是程序输出:

DllMain reason DLL_PROCESS_ATTACH
DllMain reason DLL_THREAD_ATTACH
dll.cpp: thread started
DllMain reason DLL_PROCESS_DETACH
joining thread...
dll.cpp: thread is exiting
                            <- notice how WaitForSingleObject hangs,
                               even though the thread has exited

这种方法有什么问题?

如果我碰巧从 run_thread 中删除了 Sleep(1000),这样线程在调用 WaitForSingleObject 之前完成,那么它就不会挂起:

DllMain reason DLL_PROCESS_ATTACH
DllMain reason DLL_THREAD_ATTACH
dll.cpp: thread started
dll.cpp: thread is exiting
DllMain reason DLL_THREAD_DETACH
DllMain reason DLL_PROCESS_DETACH
joining thread...
result from waiting: 0

我不明白其中的区别,这也不是一个选项,因为线程的目的是在 DLL_PROCESS_DETACH 未发出信号时不断循环。

最佳答案

I know I cannot create threads from DllMain, but what is the correct approach for creating threads in a DLL?

在主应用程序加载 dll 后(通过 LoadLibrary 隐式或显式),它调用一些由您的 dll 导出的函数,它可以做任何它喜欢的事情,包括启动线程。

I tried to create a class that wraps around it and declare a global instance of that class

全局对象的初始化(销毁)也发生在 DllMain 中; “真正的”DllMain 入口点(这是 MSDN 谈论的入口点)由 CRT 获取,CRT 使用它来初始化(销毁)globals & co。然后然后调用您的DllMain

this answer对于类似的问题(它是关于 LoadLibrary 而不是 CreateThread,但其中大部分也适用于这种情况),您可以找到更多详细信息。

What is wrong with this approach?

DllMain 中尝试做复杂的事情是错误的,特别是 explicitly discouraged 中的事情;理想情况下,DllMain 应该只是空的或做极其琐碎的工作。

最有可能的是,在这种特定情况下,被终止的线程正在尝试再次调用 DllMain 以获得 DLL_THREAD_DETACH 通知,但由于存在隐式互斥锁而被锁定这会阻止对 DllMain 的并发访问,或者因为 Windows 明确禁止 DLL_THREAD_DETACH 通知在 DLL_PROCESS_DETACH 之后到达。

这不会让我感到惊讶 - 毕竟,正如 Hans Passant 指出的那样,在代码仍在运行的情况下调用 FreeLibrary 显然是未定义的行为。不可能有一个特定的函数 (FreeLibraryAndExitThread) 让持有对库的引用的线程自动释放库并杀死自己。

关于c++ - 如何在 dll (c++) 中创建线程?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/48809595/

相关文章:

C++11 运算符""带双参数

c++ - std::this_thread::sleep_for()与main()中的sleep()

windows - 在 docker 上使用 k6 测试本地站点

python - 如何使用 "Client name:"从 python 脚本获取 perforce 工作区的 "p4 info"?

java - 在 java swing 中单击按钮时创建具有新名称的类的新对象

python - 槽在哪个线程中执行,我可以将其重定向到另一个线程吗?

c++ - 从动画文件中提取基本信息

c++ - 使用 tr1 <random> 创建非均匀整数分布

c++ - Windows 安全模式运行简单程序(至少)快 3 倍?

Android:什么时候应该使用 Handler(),什么时候应该使用 Thread?