0

I'm doing all this in C#, in Visual Studio 2008.

I want to slow down the work of my algorithm so that the user can watch it's work. There is a periodic change visible at the GUI so I added Thread.Sleep after every instance.

Problem is that Thread.Sleep, when set to at least a second, after a few instances of Thread.Sleep (after few loops) simply freezes entire GUI and keeps it that way till program completion. Not right away, but it always happens. How soon depends on the length of the sleep.

I have proof that entire program does not freeze, it's working it's thing, even the sleep is making pauses of correct length. But the GUI freezes at certain point until the algorithm ends, at which point it shows the correct final state.

How to solve this issue? Alternative to pausing algorithm at certain point?

Theodor Zoulias
  • 34,835
  • 7
  • 69
  • 104
Edmund
  • 1
  • 1
  • 1
  • If you post the relevant code it will be easier to help you. – ahsteele Mar 27 '11 at 16:00
  • try digging multhreading Edmund – Waqas Raja Mar 27 '11 at 16:01
  • There isn't any relevant code snippet to post, except entire code. I'm just using: Thread.Sleep(1000); when I want 1 second of pause. – Edmund Mar 27 '11 at 16:02
  • Check out this post http://bytes.com/topic/c-sharp/answers/687041-alternative-thread-sleep – Bala R Mar 27 '11 at 16:03
  • I expect you want to look into DoEvents() http://msdn.microsoft.com/en-us/library/system.windows.forms.application.doevents(v=VS.100).aspx – Hogan Mar 27 '11 at 16:05
  • 3
    @Hogan DoEvents? Boo. Hiss. Not much use when there is a sleep active though. – David Heffernan Mar 27 '11 at 16:07
  • [Duplicate](http://stackoverflow.com/questions/1457282/alternatives-to-thread-sleep-for-simulating-pauses) – Sanjeevakumar Hiremath Mar 27 '11 at 16:07
  • Edmund, you should do your calculation on a separate thread, letting the UI have the main thread. Is this winforms? Then have the worker thread report status back to the UI thread which will not sleep. – Mikael Svenson Mar 27 '11 at 16:08
  • 1
    I [just answered this question](http://stackoverflow.com/questions/5449956/how-to-add-a-delay-for-a-2-3-seconds/5449967#5449967). You want to use a `Timer` instead. Do not use `DoEvents`; that's not the right answer to any question. – Cody Gray - on strike Mar 27 '11 at 16:09

4 Answers4

7

First off, don't make the user wait for work that is done before they even think about when it will be finished. Its pointless. Please, just say no.

Second, you're "sleeping" the UI thread. That's why the UI thread is "locking up." The UI thread cannot be blocked; if it is, the UI thread cannot update controls on your forms and respond to system messages. Responding to system messages is an important task of the UI thread; failing to do so makes your application appear locked up to the System. Not a good thing.

If you want to accomplish this (please don't) just create a Timer when you start doing work that, when it Ticks, indicates its time to stop pretending to do work.

Again, please don't do this.

  • 1
    Agreed. And if you *do* want to allow the user to watch, at least have a throttle where they can turn the speed back up to normal once they get bored with watching it (after that first time). – Cody Gray - on strike Mar 27 '11 at 16:10
4

I'd guess everything is running out of a single thread. The user probably invokes this algorithm by clicking on a button, or some such. This is handled by your main thread's message queue. Until this event handler returns, your app's GUI cannot update. It needs the message queue to be pumped on regular basis in order to stay responsive.

Sleeping is almost never a good idea, and definitely not a good idea in the GUI thread. I'm not going to recommend that you continue to use sleep and make your GUI responsive by calling Application.DoEvents.

Instead, you should run this algorithm in a background thread and when it completes it should signal so to the main thread.

David Heffernan
  • 601,492
  • 42
  • 1,072
  • 1,490
  • Nice answer -- I said look into -- you explained. – Hogan Mar 27 '11 at 16:10
  • 1
    @Hogan: I think you misunderstood David's answer. He's not recommending that you "look into" `DoEvents` at all. In fact, he's recommending that you look **away**. It's not the correct answer; it's a dirty hack for those who are using the wrong solution in the first place. `DoEvents` is going to create more problems here than it will help. – Cody Gray - on strike Mar 27 '11 at 16:12
  • @Hogan The answer was not re-written. – David Heffernan Mar 27 '11 at 16:18
  • @Cody -- Understanding what `DoEvents()` does explains why the OP's program did not work. Armed with this knowledge the re-design is clear. I stand by the OP needing to understand `DoEvents()` and the windows message pump. – Hogan Mar 27 '11 at 16:30
  • @Hogan: Nowhere did any of your comments mention the Windows message pump. I'd have given that a +1. Mentioning `DoEvents` gets a scowl. Too many programmers use it incorrectly (which, generally, is using it at all). And it looked suspiciously to me like you were recommending it. I'm not trying to call you out here. I'm merely observing that `DoEvents` is not a good solution, even if it looks like the quick fix. Understanding *why* the problem occurs is certainly the most desirable option, but it's been my experience that pointing people in the right direction doesn't quite get them there. – Cody Gray - on strike Mar 27 '11 at 16:32
  • @Cody -- exactly the point of my first comment to this answer. My comment on the question was clearly delinquent. I would delete it in shame but I think the resulting thread is instructive. – Hogan Mar 27 '11 at 16:38
3

You are about to commit some fairly common user interface bloopers:

  • Don't spam the user with minutiae, she's only interested in the result
  • Don't force the user to work as fast as you demand
  • Don't forbid the user to interact with your program when you are busy.

Instead:

  • Display results in a gadget like a ListBox to allow the user to review results at her pace
  • Keep a user interface interactive by using threads
  • Slow down time for your own benefit with a debugger
Hans Passant
  • 922,412
  • 146
  • 1,693
  • 2,536
  • In all fairness, we don't know what the application is. Maybe the point is to actually see the algorithm work (not likely, but possible). For example, see http://www.boxcar2d.com/ , the whole point of that application is to watch a genetic algorithm "in action." – Giovanni Galbo Mar 27 '11 at 18:59
0

This depends on a lot of things, so its hard to give a concrete answer from what you've said. Still, here are some matters that might be relevant:

Are you doing this on a UI thread (e.g. the thread the form-button or UI event that triggered the work started on)? If so, it may be better to create a new thread to perform the work.

Why do you sleep at all? If the state related to the ongoing work is available to all relevant threads, can the observer not just observe this without the working thread sleeping? Perhaps the working thread could write an indicator of the current progress to a volatile or locked variable (it must be locked if it's larger than pointer size - e.g. int or an object - but not otherwise. If not locked, then being volatile will prevent cache inconsistency between CPUs, though this may not be a big deal). In this case you could have a forms timer (there are different timers in .Net with different purposes) check the status of that variable and update the UI to reflect the work being done, without the working thread needing to do anything. At most it may be beneficial to Yield() in the working thread on occasion, but its not likely that even this will be needed.

Jon Hanna
  • 110,372
  • 10
  • 146
  • 251