views:

553

answers:

4

Hi,

I'm having a bit of a problem. I want to display a progress form that just shows an animation on a when the main application preforms heavy operations.

I've done this in a thread and it works fine when the user isn't preforming any operations. But it just stops when my main application is busy.

I'm not able to put Application.ProcessMessages in between the different lines of code because I'm using 3rdparty components with heavy processing time.

My idea was to create a new process and in the process create a thread that execures the animation. Now that wouldn't stop the thread form executing when the main application performs heavy operations.

But as I see it you can only create a new process if you executes a new program.

Does any one have a solution on how to make a thread continue executing even when the main application is busy?

/Brian

+7  A: 

If your worker thread does not have a lower priority than the main thread, you don't use the Synchronize() method, don't call SendMessage() and don't try to acquire any synchronization object that the main GUI thread has already acquired, then your secondary thread should continue to work.

As the VCL isn't thread-safe people do often advise to use Synchronize() to execute code to update VCL controls synchronously in the context of the VCL thread. This however does not work if the VCL thread is itself busy. Your worker thread will block until the main thread continues to process messages.

Your application design is unfortunate, anyway. You should perform all lengthy operations in worker threads, and keep the main thread responsive for user interaction. Even with the fancy animation your app will appear hung to the user since it won't redraw while the VCL thread is busy doing other things and processes no messages. Try to put your lengthy code in worker threads and perform your animation in timer events in the main thread.

mghie
@mghie: I think you missed the fact that the heavy work is being done in the main thread, and the secondary thread is supposed to be updating progress. This is reversed logic, IMO.
Ken White
@Ken: That's what I was trying to say in the third paragraph. Maybe I should clarify it?
mghie
@mghie: Nah. When I re-read it, I think I placed to much emphasis on what you said in the first paragraph, and didn't pay enough attention to the last one. Looks good to me.
Ken White
According to Allen Bauer, Synchronize() has not used SendMessage internally since D6. Allen said: "It uses a thread-safe work queue where the "work" intended for the main thread is placed. A message is posted to the main thread to indicate that work is available and the background thread blocks on an event. When the main message loop is about to go idle, it calls "CheckSynchronize" to see if any work is waiting. If so, it processes it. Once a work item is completed, the event on which the background thread is blocked is set to indicate completion."
Mick
The source for the above comment is here: http://stackoverflow.com/questions/1806339/is-it-better-to-use-tthreads-synchronize-or-use-window-messages-for-ipc-betwee
Mick
@Mick: I'm fully aware of that correction, as that comment is to my own answer. However, for the purpose of this discussion it doesn't matter - even with `Synchronize()` calling `PostMessage()` the worker thread will block, just not on the `SendMessage()` call, but on the event. The outcome is the same, the worker thread won't progress.
mghie
+6  A: 

Your logic is backward. Your thread should be doing the "heavy work", and passing messages to your main application to update the progress or animation.

If you leave all the "heavy work" in your main application, the other thread won't get enough chances to execute, which means it won't get a chance to update anything. Besides, all access to the GUI (VCL controls) must happen in the application's main thread; the VCL isn't thread-safe. (Neither is Windows itself, when it comes to visual controls.)

Ken White
The second part is wrong, as other threads of at least the same priority will of course get a chance to work. Also, Windows visual controls are thread-safe, as interaction happens via messages which are serialized via the message queue.
mghie
Not much, if the main thread is involved in "heavy work" and doesn't yield (sleep). That's why the logic is backward; the application's main thread makes it the foreground thread, and that thread almost always gets a priority boost (unless you've configured your system specifically to act as a server and give priority to background threads). I guess I should have said "enough", instead of "won't". I'll fix that now.
Ken White
I agree re the influence priority boost may have. However, if the system has more than one core (that could be a reasonable assumption today. I tend to think mostly in terms of multiple cores now :-) and isn't completely starved of CPU cycles it should give both threads their share of CPU. But `Synchronize` is a brilliant weapon for rendering additional cores useless.
mghie
Agreed about Synchronize(). I haven't used it since I think the days of Delphi 3 or 4. I just always look at lowest common denominator when it comes to hardware. That may be because of where I work; we just got rid of the last Win98 machine 6 months ago, and the last Win2K box this week. <g>
Ken White
I agree that the logic should be inverted. Anyway the other thread will get its timeslice anyway, but because the GUI update has to happen in the main VCL thread, it won't happen until the main VCL thread is able to process updates. Moreover not all VCL controls are Windows controls.
ldsandon
@ldsandon: I never said all VCL controls are Windows controls. I said that VCL controls are not thread safe. I also said that Windows GUI controls are not thread safe, either. Two separate statements does not one sweeping statement make. :-)
Ken White
A: 

If by "Does any one have a solution on how to make a thread continue executing even when the main application is busy?" you mean that main thread is busy you should move the code that is consumming main thread to another other thread. In other words main thread should be responsible for starting and stopping actions and not executing them. Disclaymer: Actually I don't know delphy but I think/hope the concepts are quite similar to C++ or C#.

Jenea
A: 

Thanks for all of your answers! Yes, I can see that it is the reverse situation I trying to create. I was trying to jump over the fence very it is lowest. I guess I need to do a lot of reprogramming of some very old code :o(

Thanks guys...

/Brian

Brian Andersen