How to Pause backgroundWorker in Windows Form - c#

I am a newbie in .net world so i am facing some problem,please help me out, here is one of them,I have a for loop and i have a backgroundWorker control and a progressBar Control and also have 1 button that id:"btnPause".So my requirement is when my form will load the peogressbar will show the progress how much it has completed ,whenever i click on the button(btnPause) the button text need to b change and set the text as pause, then whenever i clicked again on that button it need to be resume from the value it got paused.Please help me.
Thanks in advance.

My approach to this would be to use a boolean flag to let me know whether or not the operation is paused (and perhaps a second one letting me know whether or not the operation is cancelled). When the user presses the pause button, you set the IsPaused flag to true so that when the worker begins processing the next item, it can check this flag and know to go into a wait state.
There are a few ways to keep the BackgroundWorker in this paused state. My approach would be to use a ManualResetEvent. This allows the BackgroundWorker thread to enter a sleep state and come out when the event is set. I think this is better than using a while loop with a sleep body because the thread stays asleep until the event is set, rather than waking up to check if it should still be asleep. When the user wishes to continue, it can set this event and let the Background worker continue.
So the code would look a little like this:
private void backgroundWorker_doWork(object sender, DoWorkEventArgs args)
{
//Initialize any pre-work stuff here.
while(!finished)
{
if (Paused)
m_evtPause.WaitOne();
if (Cancelled)
break;
//lengthy thread procedure code.
}
}

Try to use this
class MyWorkerClass
{
volatile bool m_bPaused = false;
// Public property to control worker execution
public bool Paused
{
get { return m_bPaused; }
set { m_bPaused = value; }
}
long ThreadFunc (BackgroundWorker worker, DoWorkEventArgs e)
{
...
// While Paused property set to true
while (m_bPaused)
{
// Pause execution for some time
System.Threading.Thread.Sleep (100);
}
}
}

Related

Pause and resume a thread c#

I am trying to pause a thread in my function which will then be resumed when a button is clicked. Windows form application
private readonly AutoResetEvent mre = new AutoResetEvent(false);
public void InstINP( int IntAcc)
{
BtnInp.Enabled = true; //enable text box
MessageBox.Show("Please input a value");
mre.WaitOne();
}
void BtnInp_Click(object sender, EventArgs e)
{
LblACC.Text = TxtInput.Text; //print to accumulator label
BtnInp.Enabled = false; //disable button
mre.Set();
}
This is what my code looks like. I want to pause where it says mre.WaitOne(); and resume where it says mre.Set().
However, when this code runs I am unable to press any buttons on my program or interact with the program, meaning I am unable to resume the program.
You are correct.
mre.WaitOne() does pause the thread.
mre.Set() does resume the thread.
The additional fact you probably already knew:
A paused thread doesn't do any processing.
And the thing you failed to think about:
You are pausing the thread that processes button clicks.
If you want to pause some bit of logic, instead of an entire thread, you can use a C# task for that:
Create a TaskCompletionSource, say tcs = new TaskCompletionSource<bool>()
Pause with await tcs.Task;
Resume with tcs.SetResult(true);
Use of await will pause the operation in progress and return to processing other events, like button clicks.
The way this works is that the C# compiler automatically splits up your code into multiple function calls, so the first one can return to the message dispatch loop, and the remaining code can be called later when the Task completes. The await keyword marks where the compiler will do this splitting.
Important note: TaskCompletionSource cannot be reset and reused like AutoResetEvent. You'll have to construct a new one for each pause/resume cycle.

Stop the GUI even that there is a while(true) loop

I can't stop my app because I have a while loop, so the gui doesn't let me click the stop button, it looks something like:
private void btnStart_Click(object sender, EventArgs e)
{ while(true)
{
//some code here
}
}
//some methods here
private void btnStop_Click(object sender, EventArgs e)
{
Application.Exit();
}
Firstly if you're running some sort of long running background job then you should not be doing that in the UI thread, because as you state, you cannot then do anything else in the UI thread to stop the loop. You'll need to defer that work to a secondary thread, or a timer, or something outside of the context of the UI thread. You can Google many different ways to achieve this.
Secondly, if you need to stop the loop then change the while condition for the loop from true to some other monitorable condition, e.g. a variable called keepRunning, which you can then set from within the btnStop_Click method. Of course if you adopt my advice in the first point then there may be some other way to stop the loop from running, e.g. if it's a timer then you can stop that timer in the appropriate way.
Thirdly, you should wait for the background operation to stop before closing the application.

SQL Query inside BackgroundWorker

I am looking for implementation of background worker and progress bar. All I can find is a simulation using the Threading.Sleep(). Samples are all working but its not working if change the simulation to actual SQL query.
Where should I insert the query in below code, please help. .NET-2.0
void m_oWorker_DoWork(object sender, DoWorkEventArgs e)
{
// The sender is the BackgroundWorker object we need it to
// report progress and check for cancellation.
//NOTE : Never play with the UI thread here...
for (int i = 0; i < 100; i++)
{
Thread.Sleep(100);
// Periodically report progress to the main thread so that it can
// update the UI. In most cases you'll just need to send an
// integer that will update a ProgressBar
m_oWorker.ReportProgress(i);
// Periodically check if a cancellation request is pending.
// If the user clicks cancel the line
// m_AsyncWorker.CancelAsync(); if ran above. This
// sets the CancellationPending to true.
// You must check this flag in here and react to it.
// We react to it by setting e.Cancel to true and leaving
if (m_oWorker.CancellationPending)
{
// Set the e.Cancel flag so that the WorkerCompleted event
// knows that the process was cancelled.
e.Cancel = true;
m_oWorker.ReportProgress(0);
return;
}
}
//Report 100% completion on operation completed
m_oWorker.ReportProgress(100);
}
By "the query", it sounds like you only have one operation to do. This makes a progress bar tricky, since there is no way of really measuring the progress of an SQL query. It can't tell you how much longer it is going to be. You might just want to use the non-committal infinite scrolling busy indicator while you perform the query.
You should execute any sql query, which is the real task of this background worker, just after checking for CancellationPending.

Awaken a task while sleeping

I have a task that runs periodically 10 second. I do some picturebox refreshing processes by reading database. What i want is to invoke or awaken the thread and do the refresh operation when i click a button immidiately. In short, i want the refresh task to be driven by not only time but also event together. Is this possible? If yes, how? The code block for the task is shown below.
while (true)
{
// do some refresh operation
Thread.Sleep(10000);
}
void button1_Click(object sender, EventArgs e)
{
// invoke or awaken thread
}
First off I'd advise you to drop the Thread + Sleep + Invoke combo for timed operations. It's very ugly. There are timer classes for both WinForms and WPF to do these three things automatically (update the GUI periodically from the dispatcher thread). Check out System.Windows.Forms.Timer and System.Windows.Threading.DispatcherTimer.
Now for your specific question, you could simply define a common method for updating the GUI with what you need and call it both from the timer code and from a button handler.
Create an AutoResetEvent:
protected AutoResetEvent _threadCycle;
_threadCycle = new AutoResetEvent(false);
when you want to wait do:
_threadCycle.WaitOne(delay, false);
and when you want to set the event, effectually letting the thread to continue:
_threadCycle.Set();
BONUS:
when you do _threadCycle.WaitOne(delay, false); you will get a return value, true or false, that you can check to see if the timeout did expire or you are continuing because of the manually set event.
BTW:
that will ONLY work if you are doing your task in an alternate thread. If you use main thread, you will get stuck with waiting for the timeout completion anyway. Maybe it will be the best to use #Tudors answer, and get this option only as 'through the thorns' way.
You should use a AutoResetEvent for this.
What you do is something like (assuming your AutoResetEvent is called 'signal'):
while (true)
{
signal.WaitOne(10000);
...
}
And in your button handler, just do:
signal.Set();

In C#, wait on the mainthread while continuing to process UI updates? (.NET 2.0 CF)

I want to otherwise block code execution on the main thread while still allowing UI changes to be displayed.
I tried to come up with a simplified example version of what I'm trying to do; and this is the best I could come up with. Obviously it doesn't demonstrate the behavior I'm wanting or I wouldn't be posting the question. I just hope it gives some code context to back my poor explanation of the problem I'm hoping to solve.
Within a button click handler on a form I have this:
private void button2_Click(object sender, EventArgs e)
{
AutoResetEvent autoResetEvent = new AutoResetEvent(false);
new Thread(delegate()
{
// do something that takes a while.
Thread.Sleep(1000);
// Update UI w/BeginInvoke
this.BeginInvoke(new ThreadStart(
delegate() {
this.Text = "Working... 1";
this.Refresh();
Thread.Sleep(1000); // gimme a chance to see the new text
}));
// do something else that takes a while.
Thread.Sleep(1000);
// Update UI w/Invoke
this.Invoke(new ThreadStart(
delegate() {
this.Text = "Working... 2";
this.Refresh();
Thread.Sleep(1000); // gimme a chance to see the new text
}));
// do something else that takes a while.
Thread.Sleep(1000);
autoResetEvent.Set();
}).Start();
// I want the UI to update during this 4 seconds, even though I'm
// blocking the mainthread
if (autoResetEvent.WaitOne(4000, false))
{
this.Text = "Event Signalled";
}
else
{
this.Text = "Event Wait Timeout";
}
Thread.Sleep(1000); // gimme a chance to see the new text
this.Refresh();
}
If I didn't set a timout on the WaitOne() the app would deadlock on the Invoke() call.
As to why I'd want to do this, I've been tasked with moving one subsystem of an app to do work in a background thread, but still have it block user's workflow (the main thread) only sometimes and for certain types of work related to that subsystem only.
You want to use the "BackgroundWorker" class, which will take most of this pain out of this for you.. but as mentioned before, you'll also want to structure it so that the main thread is updating the UI and the worker is doing the heavy lifting.
It is easyer then you might think.
Suggestion: when you need a thread to perform some occasional work, get it from the threadpool, so you will not need strange/error prone recycling code.
When you want something on another thread to update your UI, you just need a reference to the form and to call Form.Invoke passing the UI code you want the main thread to execute; it's a best pactice, in an event, to release the UI thread as soon as possible.
Ie:
private void button1_Click(object sender, EventArgs e)
{
// this is the UI thread
ThreadPool.QueueUserWorkItem(delegate(object state)
{
// this is the background thread
// get the job done
Thread.Sleep(5000);
int result = 2 + 2;
// next call is to the Invoke method of the form
this.Invoke(new Action<int>(delegate(int res)
{
// this is the UI thread
// update it!
label1.Text = res.ToString();
}), result);
});
}
Hope this helps you:)
EDIT: I am sorry, I didn't read the "blocking user workflow" part.
WindowsForms is not designed to do that, blocking the main thread is BAD (it handles the messages from the OS).
You don't have to block the user workflow via freezing a form (which would then be considered "Not Responding" by windows), the way to block user workflow is by disabling any control you want (with the Invoke method above if from another thread), even the entire form!!
Common activities which 'block' the main thread are things like opening messages boxes or modal dialog. The main code appears to block at the MessageBox or ShowDialog call.
The way those items work (and MessageBox is just a specialized modal dialog) is that they contain their own message pump while they're blocking.
Although it's a nasty hack, you can do something like this in your app by looping calling Application.DoEvents() to keep the user messages pumping while you're waiting for your other task to complete. You need to be careful because all sorts of nasty things might lead from pumping messages like this - for example someone close the form or reenter your current message handler - the modal dialogs avoid this by effectively disabling input from the form which launches them.
I did mean to say that BackgroundWorker is a better solution, if you can make it fit. I sometimes combine it with a modal 'progress dialog' to give me the background thread / message pumping and the blocking of the UI thread.
Edit - to expand on the last bit:
One approach I've used is to have a 'progress form' class, which takes a BackgroundWorker object as a constructor parameter, and contains handlers for the progress and completion events of the background worker which gets passed to it.
The form which wants the work done creates the background worker and hooks up the 'work' event (can't remember what it's called right now), and then creates a progress dialog to which it passes the background worker. It then modally shows the progress dialog, which means it will wait (but pumping messages) until the progress dialog closes.
The progress form is responsible for starting the BackgroundWorker from its OnLoad override, and closes itself when it sees the BackgroundWorker complete. Obviously you can add message text, progress bars, cancel buttons, whatever to the progress form.
structure your app so that the main thread only performs UI updates, and all other work is done on secondary threads via a work queue; then add a waiting-for-godot flag to your main thread and use it to guard the method that adds items to the work queue
out of curiosity: why do you want to do this?
You should probably restructure your code as others have suggested, but depending on the behavior you're looking for, you might also want to have a look at using a Thread.Join on your background worker thread. Join actually allows the calling thread to process COM and SendMessage events while it waits for the other thread to finish. This seems like it could be dangerous in come cases, but I've actually had a couple scenarios where it was the only way to wait for another thread to finish cleanly.
Thread..::.Join Method
Blocks the calling thread until a
thread terminates, while continuing to
perform standard COM and SendMessage
pumping.
(from http://msdn.microsoft.com/en-us/library/95hbf2ta.aspx)
I agree with the others that are suggesting you use Background Worker. It does the heavy lifting and allows the UI to continue. You can use the Report Progress of Background Worker to initiate times where the Main Form can be set to be disabled while it performs the actions in the background and then re-enable once the 'certain instances' have completed processing.
Let me know if this helps!
JFV
If you could adjust your code so that you set a flag once a process has begun and then check that in the UI before you start an additional operation I think you'd have a much easier time coding this. I would create a delegate that could be called from the thread in the threadpool or user created thread to update on progress in the UI. Once the background process has been completed switch the flag and now normal UI operations can continue. The only caveat you need to be aware of is that when you update UI components you must do it on the thread they were created on, the main/UI thread. In order to accomplish this you can call the Invoke() method on any control that lives on that thread and pass it the delegate and parameters you need to call it.
Here's a link to a tutorial I wrote some time ago about how to use Control.Invoke():
http://xsdev.net/tutorials/pop3fetcher/
Just a code snippet: don't have much time sorry :)
private void StartMyDoSomethingThread() {
Thread d = new Thread(new ThreadStart(DoSomething));
d.Start();
}
private void DoSomething() {
Thread.Sleep(1000);
ReportBack("I'm still working");
Thread.Sleep(1000);
ReportBack("I'm done");
}
private void ReportBack(string p) {
if (this.InvokeRequired) {
this.Invoke(new Action<string>(ReportBack), new object[] { p });
return;
}
this.Text = p;
}
It is best to dispatch the work but if you must, maybe something like this. Just call this method to wait for the signal rather than calling the waitone.
private static TimeSpan InfiniteTimeout = TimeSpan.FromMilliseconds(-1);
private const Int32 MAX_WAIT = 100;
public static bool Wait(WaitHandle handle, TimeSpan timeout)
{
Int32 expireTicks;
bool signaled;
Int32 waitTime;
bool exitLoop;
// guard the inputs
if (handle == null) {
throw new ArgumentNullException("handle");
}
else if ((handle.SafeWaitHandle.IsClosed)) {
throw new ArgumentException("closed wait handle", "handle");
}
else if ((handle.SafeWaitHandle.IsInvalid)) {
throw new ArgumentException("invalid wait handle", "handle");
}
else if ((timeout < InfiniteTimeout)) {
throw new ArgumentException("invalid timeout <-1", "timeout");
}
// wait for the signal
expireTicks = (int)Environment.TickCount + timeout.TotalMilliseconds;
do {
if (timeout.Equals(InfiniteTimeout)) {
waitTime = MAX_WAIT;
}
else {
waitTime = (expireTicks - Environment.TickCount);
if (waitTime <= 0) {
exitLoop = true;
waitTime = 0;
}
else if (waitTime > MAX_WAIT) {
waitTime = MAX_WAIT;
}
}
if ((handle.SafeWaitHandle.IsClosed)) {
exitLoop = true;
}
else if (handle.WaitOne(waitTime, false)) {
exitLoop = true;
signaled = true;
}
else {
if (Application.MessageLoop) {
Application.DoEvents();
}
else {
Thread.Sleep(1);
}
}
}
while (!exitLoop);
return signaled;
}
I went with something I haven't seen posted yet which is to use MessageQueues.
The MainThread blocks while waiting for the next message on a queue.
The background thread posts different types of messages to the MessageQueue.
Some of the message types signal the MainThread to update UI elements.
Of course, there is a message to tell the MainThread to stop blocking and waiting for messages.
Seems over the top considering the windows message loop already exists somewhere, but it works.

Categories

Resources