Click to See Complete Forum and Search --> : multithreading problem


Dman832
August 24th, 2005, 10:13 AM
I am using VC++ in visual studio dotNET. I wrote a program that has several threads running doing stuff, and a dialog box that is updated by the main thread. Everything works well when I hit "run" in the development environment. But when I run the executable, everything seems fine, but if I so much as click anything outside of the dialog box window, the window does not get updated again, it does not repaint, and it appears to have stopped responding. The other threads, however, are still running, and when they finish, the main window is updated with all the information that it should have been displaying along the way. I am a little new to the ms environment, and I thought that running through the development environment and running the .exe should be the same. Does anyone know what is going on here?

I could really use some help.

Axter
August 24th, 2005, 11:47 AM
You should have a function similar to the following:

void CMyDlg::DoEvents()
{
MSG msg;

while ( ::PeekMessage(&msg, NULL, 0, 0, PM_NOREMOVE ) )
{
if ( ::GetMessage(&msg, NULL, 0, 0))
{
::TranslateMessage(&msg);
::DispatchMessage(&msg);
}
else
{
break;
}
}
}


Then you're threads should call this DoEvents function on a routine bases.
A good place to call this function is inside any loop you have in your threads. Just added to the top of the loop, so it's the first line of code within the loop.
That should fix your refresh problem.

Andreas Masur
August 24th, 2005, 01:18 PM
Well...are you doing any kind of lengthy process within the mai thread? Having the work separated the work to different worker threads, they should basically not influence the main one. Are your workerthreads run in endless loops?

Andreas Masur
August 24th, 2005, 01:19 PM
[ Redirected thread ]

JohnCz
August 24th, 2005, 03:09 PM
Then you're threads should call this DoEvents function on a routine bases.
A good place to call this function is inside any loop you have in your threads. If worker threads are already running in addition to main, what would be a reason for establishing a local message loop?

Dman832
August 25th, 2005, 10:56 AM
Well,
The main thread is in a loop like this: Print a status message in one of the window's fields with SetWindowText, Update the window with UpdateWindow, and sleep for 500 ms. the other threads are doing heavy computation, but kill themselves as soon as they're done. The main thread's loop finished as soon as the other threads are gone. Everything worked fine when run through the development environment, but when it is run as the .exe, it works fine until I click out of the window, then it says (Not Responding) at the top. The other threads are still working, though, and when they are done, everything is normal again and the final results are displayed as they should be.

Axter
August 25th, 2005, 11:04 AM
Well,
The main thread is in a loop like this: Print a status message in one of the window's fields with SetWindowText, Update the window with UpdateWindow, and sleep for 500 ms. the other threads are doing heavy computation, but kill themselves as soon as they're done. The main thread's loop finished as soon as the other threads are gone. Everything worked fine when run through the development environment, but when it is run as the .exe, it works fine until I click out of the window, then it says (Not Responding) at the top. The other threads are still working, though, and when they are done, everything is normal again and the final results are displayed as they should be.

Try adding the DoEvents function I posted, and then call this function from your main thread within the main loop.

I'm sure it will fix the problem.

Dman832
August 25th, 2005, 11:13 AM
ok, I will try that now.

Dman832
August 25th, 2005, 11:30 AM
It works, HOORAY...now I need to read a little and figure out what I just did...

Thanks a bunch, I was in quite a bind.

MrViggy
August 25th, 2005, 11:31 AM
A much better method would be to use messages. Post a message from the worker thread to the GUI thread. By putting your GUI thread to sleep, you pretty much guarentee that it will *not* respond to *any* messages for 500ms. If the loop that is sleeping is pretty tight, then you're sleeping most of the time, and you get the behavior you're seeing.

Let the framework's message loop work for you. Create some user defined messages, then when the threads want to update the display, they just post it into the GUI's message queue.

http://msdn.microsoft.com/library/default.asp?url=/library/en-us/winui/winui/windowsuserinterface/windowing/messagesandmessagequeues/messagesandmessagequeuesreference/messagesandmessagequeuesfunctions/postmessage.asp
http://msdn.microsoft.com/library/default.asp?url=/library/en-us/wceshellui5/html/wce50lrfwmuser.asp

Viggy

Dman832
August 25th, 2005, 11:36 AM
Yes, I will try to make the message loop work for me, now that is atleast works, I can spend some time getting it to work better. I put the Sleep() in there not because really I need it, but because I don't know how to time anything. I want to print something in my window every half second or so, is there a better way than Sleep() to wait for 500ms ? But also, when I remove the call to Sleep(), I was still seeing the exact same behavior.

MrViggy
August 25th, 2005, 11:40 AM
A timer is a better way to wait. Remember, when you Sleep a thread, it will not execute at all for that time period.

And, yep, removing the Sleep will cause the same behavior, because you're not letting the message loop run. The message loop does things like re-fresh the display; passes mouse mesasges to the window (for moving the window); and other things. If you don't respond to those messages, your app will appear frozen, and blank. Incidentally, if you're running XP, they added a new feature to allow you to move windows that are not responding (you'll see TWO of your applciation in the task manager; one is the dummy window that the OS created because your window is not responding).

http://msdn.microsoft.com/library/default.asp?url=/library/en-us/winui/winui/windowsuserinterface/windowing/timers/usingtimers.asp

Viggy

Axter
August 25th, 2005, 11:41 AM
A much better method would be to use messages. Post a message from the worker thread to the GUI thread. By putting your GUI thread to sleep, you pretty much guarentee that it will *not* respond to *any* messages for 500ms. If the loop that is sleeping is pretty tight, then you're sleeping most of the time, and you get the behavior you're seeing.

Viggy

If by sleep, you mean actually calling the Sleep function, then that would be less efficient and have a higher probability of failing.

The logic in the DoEvent function is more efficient and more reliable then calling the Sleep() API function when it comes to getting screen refresh/updates.

JohnCz
August 25th, 2005, 11:43 AM
See this thread for a sample (http://www.codeguru.com/forum/showthread.php?p=1214024#post1214024) that does not use local message loop. Consider using this approach instead of local message loop.
Local message loop was used widely in 16-bit Windows that was not multithreaded.

Remove long processing from a main thread and move it to a worker thread (simulated in a sample)

MrViggy
August 25th, 2005, 11:45 AM
If by sleep, you mean actually calling the Sleep function, then that would be less efficient and have a higher probability of failing.

The logic in the DoEvent function is more efficient and more reliable then calling the Sleep() API function when it comes to getting screen refresh/updates.
Well, the OP said that he/she used the Sleep function. I'm not condoning use of Sleep, actually I don't think one should use Sleep. The only time I've used it was to give up the rest of the timeslice for my GUI thread (no use allowing the framework to continue it's housekeeping of you've got another thread that wants to do real work).

As for the message loop you posted, I tend to think that unless I'm using a single threaded app, putting message loops in your code is kludgy. The framework already has a method for doing what the OP wants, namely user defined messages. If you've got a worker thread, that updates your GUI thread with progress information, why put the GUI thread into a loop, waiting on the worker thread. Just create some user messages, and let the framework handle all the message processing. Especially if you're using MFC! ;)

Viggy

Dman832
August 25th, 2005, 11:50 AM
Yes, I have learned that that is basically the only time one would ever appropriately use sleep. I thought I could get by using it as a timer...wrong...

MrViggy
August 25th, 2005, 12:29 PM
Just keep in mind that Windows is an event driven system (well, just about any GUI system is). Events are created and dispatched to various threads/processes. You never want to create long loops in code that runs the main message loop (i.e. your GUI thread). I know that when I started out programming on Windows, once I realized this, the light bulb went on, and problems got a little easier to solve!

;)

Viggy

Dman832
August 25th, 2005, 01:52 PM
yeah, I'm fairly new to the whole idea of messages and events, as I haven't really worked on a GUI before, and in the past I almost exclusively programmed on Linux machines.
But the lightbulb is definately getting brighter!

Thanks again for helping.

Dman832
August 25th, 2005, 02:16 PM
Hey this is a little off topic, but I was reading through the page on worker threads and saw the thing about making sure to declare global flags as volatile. Can I declare a struct as volatile? or would I have to make each variable in the struct volatile? or both...?

Axter
August 25th, 2005, 02:51 PM
You can declare a struct as volatile

Dman832
August 25th, 2005, 02:54 PM
great. thanks.