Почему переменная аргумента потока beginthreadex не обновляется в родительском потоке

У меня есть поток, который создает скрытое окно с целью получения сообщений 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,

Я проверил в потоке, что он создается, и убедился, что я не пытаюсь получить доступ к дескриптору до того, как поток его создаст.

Что мне здесь не хватает?

-1

Решение

Вашему коду не хватает необходимой синхронизации. Что у вас здесь есть гонка данных. Таким образом, то, что вы получаете, является строго неопределенным поведением. Скорее всего, случится так, что компилятор просто не получит значение 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.

1

Другие решения

Других решений пока нет …