为什么 beginthreadex 线程参数变量不在父线程中更新
Why is beginthreadex thread argument variable not updating in parent thread
我有一个创建隐藏 window 的线程,目的是根据电源状态接收 WinAPI 消息。我需要从线程中获取创建的 window 的 HWND
,以便我可以抛出一条 WM_QUIT
消息来关闭 window 并优雅地结束线程:
主要:
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
.
进行更新
我已在线程中验证它正在创建,并且我已验证我不会在线程创建它之前尝试访问该句柄。
我在这里错过了什么?
您的代码缺少必要的同步。你这里有一个 data race. Thus, what you get is strictly undefined behavior. What will most likely happen is that the compiler simply does not re-fetch the value of hiddenWindowHandle
from memory in every iteration of the loop, since it can simply assume that the value does not change. One possible solution would be to make hiddenWindowHandle
an std::atomic
and have the main thread perform a busy wait until the value changes from NULL
. Alternatively, you could put all access to the shared variable into a critical section locked by a mutex, or use a condition variable 等待值可用。
根据评论进行编辑:
因此,如果我正确理解您的代码,创建 window 的线程会收到一个指向 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 函数。
我有一个创建隐藏 window 的线程,目的是根据电源状态接收 WinAPI 消息。我需要从线程中获取创建的 window 的 HWND
,以便我可以抛出一条 WM_QUIT
消息来关闭 window 并优雅地结束线程:
主要:
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
.
我已在线程中验证它正在创建,并且我已验证我不会在线程创建它之前尝试访问该句柄。
我在这里错过了什么?
您的代码缺少必要的同步。你这里有一个 data race. Thus, what you get is strictly undefined behavior. What will most likely happen is that the compiler simply does not re-fetch the value of hiddenWindowHandle
from memory in every iteration of the loop, since it can simply assume that the value does not change. One possible solution would be to make hiddenWindowHandle
an std::atomic
and have the main thread perform a busy wait until the value changes from NULL
. Alternatively, you could put all access to the shared variable into a critical section locked by a mutex, or use a condition variable 等待值可用。
根据评论进行编辑:
因此,如果我正确理解您的代码,创建 window 的线程会收到一个指向 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 函数。