Why is beginthreadex thread argument variable not updating in parent thread - c++

I have a thread which creates a hidden window for the purpose of receiving WinAPI messages based on power state. I need to get the HWND of the created window from the thread so that I can throw a WM_QUIT message to close the window and end the thread gracefully:
Main:
HWND hiddenWindowHandle = NULL;
HANDLE PowerWindowThreadHandle = (HANDLE)_beginthreadex(0, 0, &windowsPowerThread, (void*)&hiddenWindowHandle, 0, 0);
Thread:
unsigned int __stdcall windowsPowerThread(void* data)
{
HWND hiddenWindowHandle = createHiddenWindow();
HWND hwHandle = *(HWND*)data;
hwHandle = hiddenWindowHandle;
...
The problem is that the hiddenWindowHandle is not being updated with the generated HWND.
I have verified in the thread that it's being created, and I've verified that I'm not trying to access the handle before the thread creates it.
What am I missing here?

Your code lacks the necessary synchronization. What you have here is a 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 to wait for the value to be available.
Edit based on comments:
So if I understand your code correctly, the thread that creates the window receives a pointer to the result variable in the form of a void* and then tries to communicate the result like so:
unsigned int __stdcall windowsPowerThread(void* data)
{
…
HWND hwHandle = *(HWND*)data;
hwHandle = hiddenWindowHandle;
…
}
There's two problems here. First of all, data doesn't point to an HWND, it points to an std::atomic<HWND> now, so you already have undefined behavior there. The main problem, and probably the explanation why your original code didn't just happen to work anyways, despite the data race, is that you create a new local HWND called hwHandle. This local variable is initialized with the value of whatever data points to. You then assign your result to that local variable, but never to the actual result variable.
What you want to do is more something along the lines of
unsigned int __stdcall windowsPowerThread(void* data)
{
…
HWND hiddenWindowHandle = createHiddenWindow(…);
*static_cast<std::atomic<HWND>*>(data) = hiddenWindowHandle;
…
}
You may also want to consider using std::thread instead of the raw CRT functions.

Related

Can't save CDocument in a worker thread -- object is destroyed from memory before thread starts

Overview
I need to save a CDocument in a background worker thread. There is a point in our MFC application which prompts the user to save before continuing. Normally, they are able to continue without saving, and there is no problem. However, occasionally, we need that document later in the process, so if the user clicks "No", we want to save a temp version of the file in the background without making the user wait for the save to continue.
Problem
When I launch AfxBeginThread(SaveDocumentThread, &threadInput) the &threadinput has been cleared from memory before the SaveDocumentThread starts.
Code
BOOL SPackagerDoc::OnSaveDocument( IN LPCTSTR lpszPathName)
{
ProcessDocumentThreadInput threadInput(this, lpszPathName);
// Temp Save Mode
if (m_bTempMode)
{
m_TempSaveThread = AfxBeginThread(SaveDocumentThread, &threadInput);
// This fixes the problem, but is considered unstable
// if (m_TempSaveThread->m_hThread)
// WaitForSingleObject(m_TempSaveThread->m_hThread, 500);
return TRUE;
}
// Normal save mode
SFileLoadingDialog loadingDialog(SFileLoadingDialog::SAVE, lpszPathName, SaveDocumentThread, &threadInput);
BOOL result = (BOOL)loadingDialog.DoModal();
return result;
}
StUInt32 SPackagerDoc::SaveDocumentThread(IN StVoid* pParam)
{
ProcessDocumentThreadInput* input = (ProcessDocumentThreadInput*)pParam;
ASSERT_NOT_NULL(input);
ASSERT_NOT_NULL(input->pPackager);
ASSERT_NOT_NULL(input->pszPathName);
CString path_name(input->pszPathName);
BOOL result = input->pPackager->SPackagerDocBase::OnSaveDocument(path_name);
return result;
}
If I uncommend WaitForSingleObject(..., 500); then the thread starts, all the information is present, and there are no errors. But if I remove those lines then in SaveDocumentThread input is NULL and all data is zeros or garbage.
Is there a way to ensure the SaveDocumentThread has started before moving on. IE, wait for thread to start, but not for a specified amount of time (500 ms). It may be that 500 ms is not a sufficient wait time on some other computers.
Is there an "official" way to do this?
This is the issue of the scope of variable.
Following comments specified the scope of local variable threadInput.
ProcessDocumentThreadInput threadInput(this, lpszPathName); // <=== threadInput created
if (m_bTempMode)
{
m_TempSaveThread = AfxBeginThread(SaveDocumentThread, &threadInput);
// This fixes the problem, but is considered unstable
// if (m_TempSaveThread->m_hThread)
// WaitForSingleObject(m_TempSaveThread->m_hThread, 500);
return TRUE; // <=== threadInput destructed
}
Your workaround WaitForSingleObject() delays the destruction of the variable threadInput and you see the result.
To overcome the scope of local variable.
Store it in a class member variable.
Store it as a (better be smart) pointer and (better not to) handle it's destruction.
Edit:
As #Jabberwocky stated, function OnSaveDocument() might be called more than twice since it's called by background thread.
I'll suggest to refactor the save() function out and let if and else to call them seperately.
As others have pointed out, the problem is the lifetime of threadInput ends before the thread begins.
You can dynamically allocate the instance of ProcessDocumentThreadInput and pass the pointer to that instance to the thread.
auto* threadInput = new ProcessDocumentThreadInput(this, lpszPathName);
...
AfxBeginThread(SaveDocumentThread, threadInput);
However, in this case, the responsibility to release the memory gets messy.
Since you put C++11 tag in your question, you might want to make use of std::shared_ptr or std::unique_ptr and pass it to the thread, which would land you in using std::thread instead of AfxBeginThread. (BTW, I have no experience using MFC.)
BOOL SPackagerDoc::OnSaveDocument( IN LPCTSTR lpszPathName)
{
...
std::thread t(SaveDocumentThread, std::make_unique<ProcessDocumentThreadInput>(this, lpszPathName));
...
}
...
StUInt32 SaveDocumentThread(std::unique_ptr<ProcessDocumentThreadInput>&& threadInput)
{
...
}

Multithreading with _beginthread and CreateThread

I try to write a Multithreading WIN32 Application in C++, but due to i get difficulties.
One of the Window Procedure creates a Thread, which manages the output of this window. If this Window Procedure receives a message (from the other Window Procedures), it should transmit it to their Thread. At the beginning i worked with the _beginthread(...) function, what doesn't work.
Then i tried it with the CreateThread(...) function, and it worked? What did i do wrong?
(My English isn't so good, i hope you understand my problem)
Code with CreateThread(...):
DWORD thHalloHandle; // global
HWND hwndHallo; // Hwnd of WndProc4
...
LRESULT APIENTRY WndProc4 (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
static PARAMS params ;
switch (message)
{
case WM_CREATE: {
params.hwnd = hwnd ;
params.cyChar = HIWORD (GetDialogBaseUnits ()) ;
CreateThread(NULL, 0, thHallo, &params, 0, &thHalloHandle);
return 0 ;
}
...
case WM_SPACE: {
PostThreadMessage(thHalloHandle, WM_SPACE, 0, 0);
return 0;
}
...
}
Code with _beginthread(...):
...
case WM_CREATE: {
params.hwnd = hwnd ;
params.cyChar = HIWORD (GetDialogBaseUnits ()) ;
thHalloHandle = (DWORD)_beginthread (thHallo, 0, &params) ;
return 0;
}
...
case WM_SPACE: {
PostThreadMessage(thHalloHandle, WM_SPACE, 0, 0);
return 0;
}
...
thHallo for CreateThread:
DWORD WINAPI thHallo(void *pvoid)
{
static TCHAR *szMessage[] = { TEXT(...), ...};
// Some Declaration
pparams = (PPARAMS) pvoid;
while(!pparams->bKill)
{
MsgReturn = GetMessage(&msg, NULL, 0, 0);
hdc = GetDC(pparams->hwnd);
if(MsgReturn)
{
switch(msg.message)
{
// case....
}
}
}
return 0;
}
thHallo for _beginthread(...):
void thHallo(void *pvoid)
{
...
// The Same like for CreateThread
...
_endthread();
}
The _beginthread/ex() function is proving to be radically difficult to eliminate. It was necessary back in the previous century, VS6 was the last Visual Studio version that required it. It was a band-aid to allow the CRT to allocate thread-local state for internal CRT variables. Like the ones used for strtok() and gmtime(), CRT functions that maintain internal state. That state must be stored separately for each thread so that the use of, say, strtok() in one thread doesn't screw up the use of strtok() in another thread. It must be stored in thread-local state. _beginthread/ex() ensures that this state is allocated and cleaned-up again.
That has been worked on, necessarily so when Windows 2000 introduced the thread-pool. There is no possible way to get that internal CRT state initialized when your code gets called by a thread-pool thread. Quite an effort btw, the hardest problem they had to solve was to ensure that the thread-local state is automatically getting cleaned-up again when the thread stops running. Many a program has died on that going wrong, Apple's QuickTime is a particularly nasty source of these crashes.
So forget that _beginthread() ever existed, using CreateThread() is fine.
There's a serious problem with your use of PostThreadMessage(). You are used the wrong argument in your _beginthread() code which is why it didn't work. But there are bigger problems with it. The message that is posted can only ever be retrieved in your message loop. Which works fine, until it is no longer your message loop that is dispatching messages. That happens in many cases in a GUI app. Simple examples are using MessageBox(), DialogBox() or the user resizing the window. Modal code that works by Windows itself pumping the message loop.
A big problem is the message loop in that code knows beans about the messages you posted. They just fall in the bit-bucket and disappear without trace. The DispatchMessage() call inside that modal loop fails, the message you posted has a NULL window handle.
You must fix this by using PostMessage() instead. Which requires a window handle. You can use any window handle, the handle of your main window is a decent choice. Better yet, you can create a dedicated window, one that just isn't visible, with its own WndProc() that just handles these inter-thread messages. A very common choice. DispatchMessage() can now no longer fail, solves your bug as well.
Your call to CreateThread puts the thread ID into thHalloHandle. The call to _beginthread puts the thread handle into thHalloHandle.
Now, the thread ID is not the same as the thread handle. When you call PostThreadMessage you do need to supply a thread ID. You only do that for the CreateThread variant which I believe explains the problem.
Your code lacks error checking. Had you checked for errors on the call to PostThreadMessage you would have found that PostThreadMessage returned FALSE. Had you then gone on to call GetLastError that would have returned ERROR_INVALID_THREAD_ID. I do urge you to include proper error checking.
In order to address this you must first be more clear on the difference between thread ID and thread handle. You should give thHalloHandle a different name: thHalloThreadId perhaps. If you wish to use _beginthread you will have to call GetThreadId, passing the thread handle, to obtain the thread ID. Alternatively, use _beginthreadex which yields the thread ID, or indeed CreateThread.
Your problem is that you need a TID (Thread Identifier) to use PostThreadMessage.
_beginthread doesn't return a TID, it return a Thread Handle.
Solution is to use the GetThreadId function.
HANDLE hThread = (HANDLE)_beginthread (thHallo, 0, &params) ;
thHalloHandle = GetThreadId( hThread );
Better Code (see the documentation here)
HANDLE hThread = (HANDLE)_beginthreadex(NULL, 0, thHallo, &params, 0, &thHalloHandle ) ;

How to notify outside thread of main thread state without using global variables?

Say i have main thread and it is running my win32 procedure and a few worker threads to carry out functions that are clicked on by the user.
Lets say there is a change in the main function (I want 1 button to be available while another one is not, but only when the program enters a certain state (i.e by a boolean trigger or something of that nature), and notify all running threads that i want to disable to terminate?)?
Passing arguments to the thread only captures the state of the main thread at a certain point in time. What if i want to monitor the state of my main thread across different time frames or events?
I currently have a few global boolean values to flag/signal the program's current mode or state and that is how i notify the worker threads in how they should change their behavior.
Should I eliminate my use of global variables or keep them? Or if i should eliminate the global varialbes, how would i reimplement my program?
You can still pass arguments to your worker thread at construction time. But do not pass it copies of your state variables (because as you said, they "only captures the state of the main thread at a certain point in time", which is the worker thread creation time).
Instead, pass it pointers (or references) to your state variables.
Because they are pointers, your worker thread will have access to the latest data from the main thread without the need to use globals.
Below is a pseudo-code example (without any synchronization mechanism, like mutex):
DWORD MyThreadFunction( LPVOID argument );
int main()
{
bool mySyncVar = false;
bool* mySyncVarPtr = &mySyncVar;
CreateThread(
NULL, // default security attributes
0, // use default stack size
MyThreadFunction, // thread function name
mySyncVarPtr, // argument to thread function--NOTE THAT THIS IS
// A POINTER TO THE SYNC VARIABLE
0, // use default creation flags
NULL); // returns the thread identifier
for (...)
{
// Do stuffs
mySyncVar = true; // Will trigger worker thread
// ...
}
return 0;
}
DWORD MyThreadFunction( LPVOID argument )
{
bool* syncPtr = reinterpret_cast<bool*>(argument); // Remember this
// is a pointer
for (...)
{
while (false == *syncPtr)
{
// Wait...
}
// Trigger
// Update your buttons now
}
}

Variables overlap when calling thread twice in C++

I'm having a problem calling a thread more than once and the variables messing up. I'm new to threads, so I'm sure I'm missing something simple.
struct PARAMS
{
time_t secondsAtStart;
};
DWORD WINAPI ProcessChange(void* parameter) {
PARAMS* params = (PARAMS*)parameter;
Sleep(3000);
_tprintf(TEXT("Seconds: (%d)\n"), params->secondsAtStart);
return 0;
}
void FileChanged(CString filename, CString action) {
struct PARAMS *params = NULL;
params = (struct PARAMS *)malloc(sizeof(PARAMS)+1);
params->secondsAtStart = time(null);
// I've also tried it this way.
//PARAMS params;
//params.secondsAtStart = time(NULL);
HANDLE hThread = CreateThread(NULL, 0, ProcessChange, &params, 0, NULL);
// If I uncomment this, it works, but just one thread runs at a time.
//WaitForSingleObject(hThread, INFINITE);
}
If I don't uncomment the WaitForSingleObject, then the secondsAtStart variable gets corrupted. The end result I need is that if FileChanged gets called 3 times right after one another, I'm going to have the first two runs do nothing and the last one do the action.
Thanks,
Ben
Passing addresses of (or references to) local variables of a function, i.e. variables of automatic storage, to a thread causes undefined behaviour if the thread lives longer than the function.
In your code, params points to an object of dynamic storage, but the pointer itself is a local variable. You pass its address &params to the thread. This only works if by waiting for the thread to finish you guarantee the pointer lives longer than the thread. Otherwise it causes undefined behaviour, which quite naturally manifests itself in nonsensical values being printed.
Passing params instead of &params should solve the problem. (Also note that the code as written causes a memory leak; you'll need to make sure you actually free the space allocated after the thread has finished.)

Structure as parameter in AfxBeginThread

I try to pass a structure as a parameter.
Global structure:
struct ThreadParams
{
HWND window;
LIB::ServiceContainer* mrt;
};
In the main thread:
ThreadParams threadparams;
threadparams.window = (HWND) GetSafeHwnd();
threadparams.mrt = m_rt;
CWinThread* pthread1;
pthread1 = (CWinThread*) AfxBeginThread(Thread1,(LPVOID)&threadparams,THREAD_PRIORITY_NORMAL,0,0,0);
Outside the class:
UINT Thread1(LPVOID lp)
{
ThreadParams* threadparams = (ThreadParams*) lp;
HWND hmainWindow = threadparams->window;
LIB::ServiceContainer* m_rt = threadparams->mrt;
}
Although it compiles fine, I get an error at runtime (it is an unexpected error) and I guess that I mess up with the pointer m_rt. Do you see any obvious mistakes?
ThreadParams threadparams;
Note that if it is a local variable, and the function which declares it returns after creating the thread, then the thread refers to an object which doesn't exist anymore, as the local variable gets destroyed when the function returns. If that is the case, then create a new instance using new instead as:
ThreadParams * pthreadparams = new ThreadParams();
and pass it to the thread, so that it will exist even if the function which creates the thread returns. Of course, when you're done with it, you've to delete it manually.
You cannot safely access a local variable allocated in a different thread in most cases. By the time Thread1 starts up, the structure has likely already gone out of scope in the main thread. You should find another way, such as allocating the parameters with new in the main thread and deleting them when you're done with them in Thread1.