Click to See Complete Forum and Search --> : Thread synchronization issue


KaramChand03
February 10th, 2006, 10:22 AM
I have a app where I have to fetch data from a MySQL db and insert into a sqllite db (dont ask me why but I have to do it :) ).

Thus I am doing this process in another thread. I use a flag (m_stop) in the user defined structure passed in CreateThread(...).

Now while the import is going on, if a user has tried to close the application, I set the m_stop = TRUE and wait for another common flag (m_exit) to become TRUE.

m_stop remains false if the user has not asked to close the app while the process i going on. Whenever the thread work is over, it sets the flag m_exit = TRUE and returns gracefully.

In my child thread, I check for m_stop at regular intervals and if its set true, close the resource and get back cleanly.

My main code thread on WM_CLOSE looks like:


WM_CLOSE:
m_thread->m_stop = TRUE;

while ( m_thread->m_exit );

PostQuitMessage ( 0 );

break;


Even though I am checking for m_stop after every 3-4 lines in the child thread the child thread dosnt seem to be preempted and it never checks for the flag and the while clause remains there for long time.

But if I change the code to like:


WM_CLOSE:
m_thread->m_stop = TRUE;

MessageBox ( ...somvalue... );

while ( m_thread->m_exit );

PostQuitMessage ( 0 );

break;


it works.

Any idea what I am doing wrong?

MrViggy
February 10th, 2006, 11:38 AM
Your 'while' loop to check fro the thread to exit is sucking up all the CPU time. There are two options, you can use an event to signal your main thread. Or, if you don't care too much about the timing, you could do something like:
m_thread->m_stop = TRUE;
while ( m_thread->m_exit )
Sleep(500); // Sleep for a half second, to let child thread finish
PostQuitMessage ( 0 );
break;
Viggy

MrViggy
February 10th, 2006, 11:40 AM
Oh, and to answer why the message box also works; when you pop up the message box, it "blocks" your main thread, allowing the child thread to get some CPU time.

Viggy

Siddhartha
February 10th, 2006, 11:56 AM
In general, your logic (algorithm) is OK. The problem is in the artefacts (plain boolean flags) used to implement it.

But if I change the code to like:


MessageBox ( ...somvalue... );

while ( m_thread->m_exit );
it works.
I hope you realize that the statement in bold must actually be hogging CPU cycles (besides that the code in the thread that sets m_exit is not visible).

I would recommend that instead of m_stop, you -
Create an event in the main thread using CreateEvent (http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dllproc/base/createevent.asp) to get m_hStopEvent. HANDLE m_hStopEvent = CreateEvent (NULL, FALSE, FALSE, NULL);
Pass the handle as a parameter to the thread in the call to CreateThread.
When application is ready to exit, use SetEvent (http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dllproc/base/setevent.asp) in the main thread, like this -SetEvent (m_hStopEvent);
Check the event in the worker thread using WaitForSingleObject (http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dllproc/base/waitforsingleobject.asp) like this - if (WaitForSingleObject (m_hStopEvent, 0) == WAIT_OBJECT_0)

; // clean up and quit
Instead of using a boolean flag m_exit, make the main thread wait for the worker to end using -WaitForSingleObject (hThread, INFINITE);...immediately after doing the SetEvent.

This will keep the CPU free, and will make a neat solution.

Siddhartha
February 10th, 2006, 12:02 PM
[ redirected ]

Regards,
Siddhartha

MikeAThon
February 10th, 2006, 03:51 PM
I don't think it's a CPU-hog-problem caused by the while loop. The OS will still switch between threads, even if one thread is stuck in a while, and will therefore give at least some time to the child thread, during which it should be able to check on the m_stop flag and thereafter set the m_exit flag.

There's something else going on, and I believe it's related to the message pump.

(Before trying anything else, however, declare the m_stop and m_exit flags as "volatile". That might fix things, although I doubt it.)

Does your child thread use the message queue? For example, does it send messages to the main thread (i.e., SendMesssage)? If so, then here's probably what's happening.

The child thread sends a message to the main UI thread and is waiting for the UI thread to respond. Meanwhile, the user closes the app, and in the WM_CLOSE handler the UI thread enters a while loop that blocks the UI thread from processing its message queue. Since the UI thread can't process the message queue, it can't respond to the child's message; hence the child thread is stuck while it waits for the UI thread to respond to its message, and cannot progress to a point where it sees m_stop or responds by setting m_exit.

When you insert the MessageBox, however, Windows provides a temporary message pump for your app while the message box is being displayed (i.e., the modal dialog message pump). Thus, during display of the message box, messages are being pumped for you, by the OS. This allows the UI thread to respond to the message sent by the child thread, and all things go well again.

If this is the problem, then the solution is to avoid SendMessage from the child thread to the UI thread. Use PostMessage instead. SendMessage causes inter-thread dependencies that are avoided by PostMessage. The event-based solution proposed by Siddhartha, while indeed more preferred and a neater CPU-lite solution, will not solve the inter-thread dependences caused by use of SendMessage instead of PostMessage.

Mike

Arjay
February 10th, 2006, 04:34 PM
Instead of using a boolean flag m_exit, make the main thread wait for the worker to end using -WaitForSingleObject (hThread, INFINITE);...immediately after doing the SetEvent.

This will keep the CPU free, and will make a neat solution.Keep in mind that if the main thread is a UI thread, the op will need to use MsgWaitForMultipleObjects and pump messages during the wait; otherwise the main thread will hang with WFSO.

Arjay

Siddhartha
February 10th, 2006, 04:41 PM
Keep in mind that if the main thread is a UI thread, the op will need to use MsgWaitForMultipleObjects and pump messages during the wait; otherwise the main thread will hang with WFSO.I believe that in general I have kept it in my mind quite a while back. ;)

I doubt if UI responsiveness at a stage when the application was quitting would make any percievable difference given the fact that the worker thread was checking the exit-flag at regular instances and would quit without percievable delay.

Anyways, it's a point for the OP to keep in mind.

KaramChand03
February 11th, 2006, 07:17 AM
if (WaitForSingleObject (m_hStopEvent, 0) == WAIT_OBJECT_0) ;

did the trick. Actually, I was doing this earlier:

if (WaitForSingleObject (m_hStopEvent, 0) )

and it failed. Now I understood the requirement/importance of WAIT_OBJECT_0.

I even understood while a simple flag checking was not working.

Thanks all guys!