我有一个线程,该线程创建一个隐藏的窗口,以便基于电源状态接收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
更新。
我已经在线程中验证了它的创建过程,并且已经验证我在线程创建它之前没有尝试访问该句柄。
我在这里想念什么?
答案 0 :(得分:1)
您的代码缺少必要的同步。您在这里拥有的是data race。因此,您得到的是严格未定义的行为。最有可能发生的情况是,编译器在循环的每次迭代中都不会简单地从内存中重新获取hiddenWindowHandle
的值,因为它可以简单地假设该值没有改变。一种可能的解决方案是使hiddenWindowHandle
成为std::atomic
,并使主线程执行繁忙的等待,直到值从NULL
更改为止。另外,您可以将对共享变量的所有访问权限放到由mutex锁定的关键部分,或使用condition variable等待该值可用。
因此,如果我正确理解您的代码,则创建窗口的线程会以void*
的形式接收指向结果变量的指针,然后尝试像这样传达结果:
unsigned int __stdcall windowsPowerThread(void* data)
{
…
HWND hwHandle = *(HWND*)data;
hwHandle = hiddenWindowHandle;
…
}
这里有两个问题。首先,data
并不指向HWND
,而是现在指向std::atomic<HWND>
,因此您那里已经有未定义的行为。主要问题以及可能的原因是,尽管有数据争用,为什么原始代码仍然无法正常工作,原因是您创建了一个名为HWND
的新本地hwHandle
。使用data
指向的任何值初始化此局部变量。然后,将结果分配给该局部变量,而不分配给实际结果变量。
您想要做的是更多类似的事情
unsigned int __stdcall windowsPowerThread(void* data)
{
…
HWND hiddenWindowHandle = createHiddenWindow(…);
*static_cast<std::atomic<HWND>*>(data) = hiddenWindowHandle;
…
}
您可能还想考虑使用std::thread
而不是原始的CRT函数。