views:

345

answers:

3

I have a Windows Form and a class with two simple methods that run recursively in a nondeterministic way (meaning that it's unknown which recursion will be called, both can call the other)... Now, there are some points during that recursion at which I want to pause the execution and wait for a user to click on the "Next Step" button. Only after the button is pressed should the recursive functions continue. The class runs on a separate thread so it doesn't block the UI.

During that pause, the Form would simply retrieve the value from the class and display it in a listbox. Then after the button is pressed, the recursion continues until the next Pause(). I need this so the user can see what is happening in the recursion step by step. Also I need to be able to put Pause() anywhere in the recursive method (even multiple times) without causing any side-effects...

The only way that comes to my mind is to call Pause() method in which a loop checks some locked flag and then sleeps for some time (the button would then set the flag), but I had some bad experiences with Thread.Sleep() in Windows Forms (locking the UI) so I am looking at another options.

Is there any clean way to do this?

+2  A: 

Use a AutoResetEvent object.

Call the .WaitOne method on it from your thread to pause it, and call the .Set method on it from your button to unpause it.

Lasse V. Karlsen
An `AutoResetEvent` won't work as intended in this scenario.
JSBangs
Won't work in this scenario because...?
Lasse V. Karlsen
It works, so there's no because :)
kornelijepetak
I know that, I was interested in knowing what JS Bangs meant by his comment. But then I saw his answer afterwards, clearly he changed your question. Anyway, if you found your solution, that's all that matters :)
Lasse V. Karlsen
I misunderstood the requirements, it turns out, and was thinking that Pause() was initiated by a user action. In that case, you can't use `AutoResetEvent`, because you want the event to remain set until the user clicks on the Pause button.
JSBangs
+5  A: 

Use a ManualResetEvent that is initialized to true, so it begins set. At a well-known place in one method or the other (or both), wait for the event. Most of the time, the event will be set so the background thread will continue immediately. When the user clicks Pause, however, reset the event, causing the background thread to block the next time it reaches the event. When the user next clicks "Resume", set the event, allowing the background thread to continue again.

There's no reason that the UI thread should ever block in this scenario.

JSBangs
This worked with a little modification because the user does not pause, the function itself pauses. The user only performs the step. But I've put Reset() and WaitOne() in my Pause() and then on button click I simply Set(). It works as intented. It's funny how I never noticed this class.
kornelijepetak
That is how AutoResetEvent works. It automatically resets when a thread successfully waits on it.
Lasse V. Karlsen
Yes, AutoResetEvent works too for my scenario and actually makes a shorter code (by one line). So now I can only call WaitOne() in my Pause() with rest of the code left unchanged.
kornelijepetak
+1  A: 

This is a good place to use a Mutex in a non-standard way. Just have your background thread take and release the Mutex when it's in a position where it's ok to wait.

Have your GUI thread take the Mutex when it wants to block the background thread, and release it when it's ok for it to run.

That way the background thread will wait when it should, and will simple blaze in and out of the Mutex when it's allowed to run.

Think of the 'right to run' as a resource that the critical section is protecting.

like this

// this object has to be visible to both threads
System.Threading.Mutex mtx = new Mutex();

// worker thread does this wherever it's ok for it to pause
mtx.WaitOne();
mtx.ReleaseMutex();

// main thread does this to pause the worker
Mtx.WaitOne();

// main thread does this this to unpause it.
mtx.ReleaseMutex();
John Knoeller