为什么 beginthreadex 线程参数变量在父线程中没有更新

Why is beginthreadex thread argument variable not updating in parent thread

本文关键字:线程 更新 beginthreadex 参数 变量 为什么      更新时间:2023-10-16

我有一个线程,它创建了一个隐藏窗口,用于根据电源状态接收 WinAPI 消息。我需要从线程中获取创建的窗口的HWND,以便我可以抛出一条WM_QUIT消息来关闭窗口并优雅地结束线程:

主要:

HWND hiddenWindowHandle = NULL;
HANDLE PowerWindowThreadHandle = (HANDLE)_beginthreadex(0, 0, &windowsPowerThread, (void*)&hiddenWindowHandle, 0, 0);

线:

unsigned int __stdcall windowsPowerThread(void* data)
{
HWND hiddenWindowHandle = createHiddenWindow();
HWND hwHandle = *(HWND*)data;
hwHandle = hiddenWindowHandle;
...

问题是hiddenWindowHandle使用生成的HWND进行更新。

我已经在线程中验证了它正在创建,并且我已经验证了在线程创建句柄之前我没有尝试访问句柄。

我在这里错过了什么?

您的代码缺少必要的同步。你在这里看到的是一场数据竞赛。因此,你得到的是严格未定义的行为。最有可能发生的是,编译器根本不会在循环的每次迭代中从内存中重新获取hiddenWindowHandle的值,因为它可以简单地假设该值不会更改。一种可能的解决方案是使hiddenWindowHandle成为std::atomic,并让主线程执行繁忙的等待,直到值从NULL更改。或者,您可以将对共享变量的所有访问放入由互斥锁锁定的关键部分中,或使用条件变量等待值可用。

根据评论进行编辑:

因此,如果我正确理解您的代码,则创建窗口的线程将以void*的形式接收指向结果变量的指针,然后尝试像这样传达结果:

unsigned int __stdcall windowsPowerThread(void* data)
{
…
HWND hwHandle = *(HWND*)data;
hwHandle = hiddenWindowHandle;
…
}

这里有两个问题。首先,data不指向HWND,它现在指向一个std::atomic<HWND>,所以你已经在那里有未定义的行为。主要问题,以及可能解释为什么你的原始代码无论如何都不能正常工作,尽管存在数据竞争,是你创建了一个名为hwHandle的新本地HWND。此局部变量使用data指向的任何值进行初始化。然后,将结果分配给该局部变量,但永远不会分配给实际结果变量。

你想做的更多的是类似的东西

unsigned int __stdcall windowsPowerThread(void* data)
{
…
HWND hiddenWindowHandle = createHiddenWindow(…);
*static_cast<std::atomic<HWND>*>(data) = hiddenWindowHandle;
…
}

您可能还需要考虑使用std::thread而不是原始 CRT 函数。