How to make Background thread pause and then continue on button click? - c#

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?

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.

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.

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();

Related

Pause button for a game c#

I just want to create a simple pause button, and perhaps another button to resume if necessary. I've been looking around and I mostly see Thread.Sleep(), which doesn't work for me because I want the pause to remain paused until the user desires.
Thread.Suspend() doesn't work because that is obsolete now.
I've also seen another solution of creating a second form, however, that doesn't seem to be working for me. Once that second form opens up, the entire program closes.
I'm not sure if this makes a difference, but my program currently uses two threads (main thread running form1 along with another thread). Ideally, everything needs to be paused.
The simpliest thing to do is to have some variable/property that the other thread can access.
Bool ShouldPause = false;
The other thread should have in it's game loop something like that :
while(true)
{
if(!ShouldPause)
{
UpdateGame();
}
Draw();
}
Then the game will proceed only when the ShouldPause variable is false.
I did it several times and it worked perfectly.
You don't want to pause the thread via some "Suspend" like functions because it will prevent from him to draw on the screen and would appear like it's not responding.
You can use Thread Signaling technique.
A good start is to take a look at ManualResetEvent Class

Backgroundworker is canceled and locked? How its possible?

I have strange issue reported by users and once reproduced by me.
I have form with various buttons and each button performs long operation.
When new buttons are clicked old operation will stops and new will be started.
And i noticed strange behaviour:
When i am clicking button sometimes operation doesnot started.
Operation cannot be started because next code:
if (!Worker.IsBusy)
{
RunReload();
}
else
{
isWorkerPendingForNewJob = true;
Worker.CancelAsync();
}
Cancel is called few times but my worker is always busy!
When i brake my project execution i noticed that it stops on lock section.
Inside this lock i am just creating some objects that are used for all processes.
Brackpoints on image never hits.
Why backgroundworked is always busy and locked on this line?
When you call CancelAsync(), it just set the flag CancellationPending to true. You must manually check periodically this flag in your BackgroundWorker work function and interrupt it yourself. Are you doing this already?
Here is the related MSDN page.
Also, you must ensure that WorkerSupportsCancellation is true to support CancelAsync.

Form Visiblity Problem

Form1.button_Click(...) {
// Show a dialog form, which runs a method <CheckBalance()> on it's OnLoad Event.
var modemDialog = new ModemDialog("COM25");
modemDialog.ShowDialog();
// the user can't see this dialog form until the method <CheckBalance()> terminates.
}
Is it possible to show first the dialog then run the specified method?
THanks.
That is correct and expected. Winforms UI is inherently single-threaded. Having a function call like "CheckBalance" in the form load event will prevent the form from showing until the form load event completes. Depending on the duration of the task, you have a number of options available to you:
If it's a fast task, compute it ahead of time before showing the form
If it's something the user may want to initiate, move it to a button on the new form, so it's only calculated on the request of the user
If it's a long running task that takes some time, you'll need to move it off in to another thread. Using a BackgroundWorker is recommended.
OnLoad occurs before the form is shown to allow you to initialise the form and variables and what not, which means it is synchronous. The form will not show until you return from that function.
If you want to asynchronously run the CheckBalance() method, then you can use a few techniques, such as utilising the Threading, ThreadPool or Tasks API to shift that work to a background thread, and returning immediately so that the form is shown.
Here is an example of using a Task to perform the same action, but asynchronously so that the form immediately shows:
Action<object> action = () => { CheckBalance(); };
new Task(action).Start();
Please note that if you access the UI thread, you'll need to beware of thread-safety and invocation.
The simple way to make sure your form is visible before CheckBalance is run is to use this code in the form load handler:
this.BeginInvoke((Action)(() => this.CheckBalance()));
This will push the execution of the CheckBalance method onto the UI thread message pump so will execute after all preceding UI code is complete.
Others are correct though that the UI will still be blocked as CheckBalance executes. You probably want to run it on a background thread to prevent this.

C# - Code processing order - strange behaviour

I have the follow button click event:
private void btnRun_Click(object sender, EventArgs e)
{
label1.Visible = true;
if (SelectDatabase())
{
if (string.IsNullOrEmpty(txtFolderAddress.Text))
MessageBox.Show("Please select a folder to begin the search.");
else
{
if (cbRecurse.Checked == false || Directory.GetDirectories(initialDirectory).Length == 0)
{
CheckSingleFolder();
}
else
{
CheckSingleFolder();
directoryRecurse(initialDirectory);
}
}
}
}
Effectively, it does a few checks and then starts some directory recursion looking for specific files. However, the very first line of code to make the label visible does not occur until after the directories have been recursed? Anybody know why this would be?
Thanks.
You're doing everything within the UI thread, which is a really bad idea - the UI doesn't get to update, react to events etc until you've finished.
You should use a background thread and update the UI with progress etc using Control.BeginInvoke, or perhaps use a BackgroundWorker.
Basically, there are two golden rules in WinForms (and similar with WPF/Silverlight):
Don't do anything which can take a significant amount of time in the UI thread
Don't touch any UI elements from any thread other than the UI thread
your whole method runs as a blocking unit currently - add an Application.DoEvents() as a workaround, but really you should be doing this kind of processing in a background thread, i.e. using a background worker.
The code is executing on the same thread which is drawing your user-interface. Therefore, while the code is executing, your UI is not being re-drawn. Once the button-click code has finished, the UI is redrawn and label1 gets drawn invisibly.
You can move your code into a separate thread using, for example, Task or BackgroundWorker. However, you cannot directly set UI properties from a different thread, so you will need to either be careful to set your UI properties from the UI thread or see this question about how to update the GUI from another thread.
The view is not updated until the code block finished. So I would propose a BackgroundWorker for the recursion part.
The explanation: the label is set to visible and it it is Invalidated (needs repainting) but the Windows message pump doesn't start repainting until it is running idle. So your code blocks it.
A simple solution is to call label1.Update() right after setting it visible.
A better solution is to move the time-consuming code to a thread (Backgroundworker).

WinForm And Looping

I have a WinForm set up and a process that loops until a button is pressed on the form.
When I try to run my code, the form does not even display. I suspect this is because the code gets stuck in the loop and doesn't get far enough to display the WinForm. How can I get the form to display and the loop to run after that point?
If you're looping because you need to do something with the GUI periodically while waiting for input, I suggest using a Timer control and its Tick event.
If you want to do non-GUI things while waiting, a more traditional timer is better suited to the task,
You should probably run the loop in a background thread. The BackgroundWorker class makes this pretty easy to do.
Don't do that.
Windows Forms (like most modern user interface development toolkits) is an event-driven framework. You should never use a loop that "waits" for something to happen; instead you want to use an event that triggers something to happen.
Essentially what's happening is this: WinForms has a loop running a message pump that listens for events from Windows and triggers C# events in response to them. Your code is executing on the same thread as that message pump (it has to, since in WinForms only one thread is allowed to touch any given control). So if you put that thread into a loop, the WinForms code that should be pumping messages isn't, and your user interface appears to hang, since it isn't responding to any messages from Windows. (If you keep clicking it, you will fill up the message queue and get a dialog box that says "This application has stopped responding, do you want to terminate?" or something like that.)
The correct solution is to do one of the following:
Use a Timer
Use a BackgroundWorker
Use a ThreadPool
Another solution that would work, but is not a good idea is:
Use Application.DoEvents() -- but please don't actually do this
Your form loading is freezing because the UI of a windows form runs in a single thread. And the logic that you put on the Load event of this form is running on that thread.
You can run your loop on a separate thread easily by using a BackgroundWorker component on your windows form. On the event DoWork of your background worker, you place the code that has the loop that should run without block your UI. On the Form.Load event, you can start the background worker component by calling the method RunWorkerAsync. On the event handler of your button, you place a code to stop the background worker by calling CancelAsync method.
The article How to: Implement a Form That Uses a Background Operation shows exactly how to accomplish it.
About your comment on not being able to update the Text of a TextBox from a your background worker component. It happens because it is not allowed to modify the state of a windows forms control from a different thread (your background worker code is running on a separated thread) MSDN documentation says:
Access to Windows Forms controls is not inherently thread safe. If you have two or more threads manipulating the state of a control, it is possible to force the control into an inconsistent state. Other thread-related bugs are possible, such as race conditions and deadlocks. It is important to make sure that access to your controls is performed in a thread-safe way.
A sample of how you can update the state of your windows forms controls from your background thread will be similar to the one below (assuming that the new value is already stored on a String variable named text):
// InvokeRequired required compares the thread ID of the
// calling thread to the thread ID of the creating thread.
// If these threads are different, it returns true.
if (this.textBox1.InvokeRequired)
{
SetTextCallback d = new SetTextCallback(SetText);
this.Invoke(d, new object[] { text });
}
else
{
this.textBox1.Text = text;
}
I borrowed this code snipped from How to: Make Thread-Safe Calls to Windows Forms Controls article. It can provide you more information about how to deal with multi-threaded windows forms.
You can use the form load event to trigger the start of the loop.
So it would handle the event Me.Load
However is it necessary for your loop to be happening inside of the UI?
This happens because your loop is keeping the window function from processing messages, such as those that tell it to repaint itself. Place a call to Application.DoEvents() inside of your loop to allow the UI to continue to function.
However, you need to ask yourself why you're looping like this in the first place. If you're, say, copying a bunch of files, this might make sense. For most tasks, though, responding to a timer tick should do the trick and won't block the UI.
You should run your loop in a background thread using the BackgroundWorker component.
Remember that the background thread cannot directly interact with the UI controls.
To report the progress on the UI, you should call the BackgroundWorker's ReportProgress method in the background thread, and handle the ProgressChanged event to update the UI.
You can call the CancelAsync method when the Button is clicked, and loop until the CancellationPending property is true.

Categories

Resources