У меня есть поток, который создает скрытое окно с целью получения сообщений 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>
теперь, так что у вас уже есть неопределенное поведение там. Основная проблема и, вероятно, объяснение того, почему ваш оригинальный код не работал так или иначе, несмотря на гонку данных, заключается в том, что вы создаете новый локальный HWND
называется hwHandle
, Эта локальная переменная инициализируется значением любого data
указывает на. Затем вы присваиваете свой результат этой локальной переменной, но не фактической переменной результата.
То, что вы хотите сделать, это что-то вроде
unsigned int __stdcall windowsPowerThread(void* data)
{
…
HWND hiddenWindowHandle = createHiddenWindow(…);
*static_cast<std::atomic<HWND>*>(data) = hiddenWindowHandle;
…
}
Вы также можете рассмотреть возможность использования std::thread
вместо необработанных функций CRT.
Других решений пока нет …