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, ¶ms, 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 ¶ms 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 ¶ms 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.)
Related
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)
{
...
}
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.
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.
I have a program that processes neural spike data that is broadcast in UDP packets on a local network.
My current program has two threads a UI thread and a worker thread. The worker thread simply listens for data packets, parses them and makes them available to the UI thread for display and processing. My current implementation works just fine. However for a variety of reasons I'm trying to re-write the program in C++ using an Object Oriented approach.
The current working program initialized the 2nd thread with:
pthread_t netThread;
net = NetCom::initUdpRx(host,port);
pthread_create(&netThread, NULL, getNetSpike, (void *)NULL);
Here is the getNetSpike function that is called by the new thread:
void *getNetSpike(void *ptr){
while(true)
{
spike_net_t s;
NetCom::rxSpike(net, &s);
spikeBuff[writeIdx] = s;
writeIdx = incrementIdx(writeIdx);
nSpikes+=1;
totalSpikesRead++;
}
}
Now in my new OO version of the program I setup the 2nd thread in much the same way:
void SpikePlot::initNetworkRxThread(){
pthread_t netThread;
net = NetCom::initUdpRx(host,port);
pthread_create(&netThread, NULL, networkThreadFunc, this);
}
However, because pthead_create takes a pointer to a void function and not a pointer to an object's member method I needed to create this simple function that wraps the SpikePlot.getNetworSpikePacket() method
void *networkThreadFunc(void *ptr){
SpikePlot *sp = reinterpret_cast<SpikePlot *>(ptr);
while(true)
{
sp->getNetworkSpikePacket();
}
}
Which then calls the getNetworkSpikePacket() method:
void SpikePlot::getNetworkSpikePacket(){
spike_net_t s;
NetCom::rxSpike(net, &s);
spikeBuff[writeIdx] = s; // <--- SegFault/BusError occurs on this line
writeIdx = incrementIdx(writeIdx);
nSpikes+=1;
totalSpikesRead++;
}
The code for the two implementations is nearly identical but the 2nd implementation (OO version) crashes with a SegFault or BusError after the first packet that is read. Using printf I've narrowed down which line is causing the error:
spikeBuff[writeIdx] = s;
and for the life of me I can't figure out why its causing my program to crash.
What am I doing wrong here?
Update:
I define spikeBuff as a private member of the class:
class SpikePlot{
private:
static int const MAX_SPIKE_BUFF_SIZE = 50;
spike_net_t spikeBuff[MAX_SPIKE_BUFF_SIZE];
....
}
Then in the SpikePlot constructor I call:
bzero(&spikeBuff, sizeof(spikeBuff));
and set:
writeIdx =0;
Update 2: Ok something really weird is going on with my index variables. To test their sanity I changed getNetworkSpikePacket to:
void TetrodePlot::getNetworkSpikePacket(){
printf("Before:writeIdx:%d nspikes:%d totSpike:%d\n", writeIdx, nSpikes, totalSpikesRead);
spike_net_t s;
NetCom::rxSpike(net, &s);
// spikeBuff[writeIdx] = s;
writeIdx++;// = incrementIdx(writeIdx);
// if (writeIdx>=MAX_SPIKE_BUFF_SIZE)
// writeIdx = 0;
nSpikes += 1;
totalSpikesRead += 1;
printf("After:writeIdx:%d nspikes:%d totSpike:%d\n\n", writeIdx, nSpikes, totalSpikesRead);
}
And I get the following output to the console:
Before:writeIdx:0 nspikes:0 totSpike:0
After:writeIdx:1 nspikes:32763 totSpike:2053729378
Before:writeIdx:1 nspikes:32763 totSpike:2053729378
After:writeIdx:1 nspikes:0 totSpike:1
Before:writeIdx:1 nspikes:0 totSpike:1
After:writeIdx:32768 nspikes:32768 totSpike:260289889
Before:writeIdx:32768 nspikes:32768 totSpike:260289889
After:writeIdx:32768 nspikes:32768 totSpike:260289890
This method is the only method where I update their values (besides the constructor where I set them to 0). All other uses of these variables are read only.
I'm going to go on a limb here and say all your problems are caused by the zeroing out of the spike_net_t array.
In C++ you must not zero out objects with non-[insert word for 'struct-like' here] members. i.e. if you have an object that contains a complex object (a std string, a vector, etc. etc.) you cannot zero it out, as this destroys the initialization of the object done in the constructor.
This may be wrong but....
You seemed to move the wait loop logic out of the method and into the static wrapper. With nothing holding the worker thread open, perhaps that thread terminates after the first time you wait for a UDP packet, so second time around, sp in the static method now points to an instance that has left scope and been destructed?
Can you try to assert(sp) in the wrapper before trying to call its getNetworkSpikePacket()?
It looks like your reinterpret_cast might be causing some problems. When you call pthread_create, you are passing in "this" which is a SpikePlot*, but inside networkThreadFunc, you are casting it to a TetrodePlot*.
Are SpikePlot and TetrodePlot related? This isn't called out in what you've posted.
If you are allocating the spikeBuff array anywhere then make sure you are allocating sufficient storage so writeIdx is not an out-of-bounds index.
I'd also check that initNetworkRxThread is being called on an allocated instance of spikePlot object (and not on just a declared pointer).
I am creating 5 thread here using ThrdFunc. Here each thread update the listBox.
I was expecting message in this way. Initially come in this way but after some time
Thread1:Adding msg
Thread2:Adding msg
Thread3:Adding msg
But after some time I get message like
Thread0:Adding msg
Thread18967654:Adding msg
Thread18967654:Adding msg
Thread18967654:Adding msg
This is the code:
for (int i = 0;i<6;i++)
{
nThreadNo = i+1;
hWndProducer[i] = CreateThread(NULL,0,(LPTHREAD_START_ROUTINE)ProducerThrdFunc,(void*)&nThreadNo,0,&dwProducerThreadID[i]);
if (hWndProducer[i] == NULL)
{
//ErrorHandler(TEXT("CreateThread"));
ExitProcess(3);
}
}
DWORD WINAPI ThrdFunc ( LPVOID n )
{
int *nThreadNo = (int*)n;
char chThreadNo[3];
memset(chThreadNo,0,3);
while(1)
{
itoa(*nThreadNo,chThreadNo,10);
char* pMsg1 = new char[100];
char* pMsg2 = new char[100];
memset(pMsg1,0,100);
memset(pMsg2,0,100);
strcpy(pMsg1," Thread No:");
strcat(pMsg1,chThreadNo);
strcat(pMsg1," Adding Msg:");
PostMessage(stThreadInfoProd.hWndHandle,UWM_ONUPDATEPRODUCERLIST,(WPARAM)pMsg1,0);
}
return 0;
}
Most likely nThreadNo is allocated on the stack. You're giving each thread a pointer to one of it's elements.
Once the function creating the threads returns, the array is no longer valid, but the thread functions are still pointing to it. The memory the threads are holding pointers to will most likely be overwritten, causing what was originally the thread ID to be overwritten with garbage.
Anything you pass another thread should generally be allocated on heap, either via malloc type functions or new, preferably new since this is C++.
For example, instead of int nThreadNo[6], use int* nThreadNo = new int[6]. However, keep in mind that you will have to delete[] the memory nThreadNo points to when you're done with it.
Well, I can't be sure because you've not given all your code.
However, it looks like nThreadNo is a local variable, defined on the stack of the main thread. You are passing the address of this variable to the threads, but you should be passing the value, or passing some heap allocated memory.
What you are doing is morally equivalent to returning from a function a pointer to a local variable, e.g.
int* foo()
{
int i;
return &i;
}
The simplest way to make your code behave is to make the following changes:
CreateThread(..., (void*)nThreadNo, ...
int nThreadNo = (int)n;
nThreadNo has to be global because you are giving a pointer to it to your new thread.