How to Stop Backgroundworker on Form'S Closing Event

How to stop BackgroundWorker on Form's Closing event?

The only deadlock-safe and exception-safe way to do this that I know is to actually cancel the FormClosing event. Set e.Cancel = true if the BGW is still running and set a flag to indicate that the user requested a close. Then check that flag in the BGW's RunWorkerCompleted event handler and call Close() if it is set.

private bool closePending;

protected override void OnFormClosing(FormClosingEventArgs e) {
if (backgroundWorker1.IsBusy) {
closePending = true;
backgroundWorker1.CancelAsync();
e.Cancel = true;
this.Enabled = false; // or this.Hide()
return;
}
base.OnFormClosing(e);
}

void backgroundWorker1_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e) {
if (closePending) this.Close();
closePending = false;
// etc...
}

How to stop BackgroundWorker on Form's Closing event to avoid RaceOnRCWCleanup error and to aovid form1 dispose before backgroundworker finish?

Suppose Bgw is you backgroundworker first you will set :

Bgw.WorkerSupportsCancellation = true;  

then in you DoWork delegate you will have to check whether Bgw.CancellationPending is true or false.

If it is true that means backgroundworker has been canceled and you will have to abort the function if not continue as it is.

Closing the form when backgroundWorker stops working

You can use the BackgroundWorker.RunWorkerCompleted event to monitor when the BackgroundWorker is done.

Occurs when the background operation has completed, has been canceled, or has raised an exception.

From there, you could close the form programmatically.

Can't stop form closing when background worker is in progress

Are you sure that myBackgroundWorker.IsBusy returns true? Have you tried setting a break point inside the check to make sure it's being called?

Are you sure that the event is hooked up properly?

If those things are true, the bug would have to be in some other part of the code.

There may also be some other handler on FormClosing setting Cancel to false, but that's probably a less likely scenario.

How to stop BackgroundWorker correctly

CancelAsync doesn't actually abort your thread or anything like that. It sends a message to the worker thread that work should be cancelled via BackgroundWorker.CancellationPending. Your DoWork delegate that is being run in the background must periodically check this property and handle the cancellation itself.

The tricky part is that your DoWork delegate is probably blocking, meaning that the work you do on your DataSource must complete before you can do anything else (like check for CancellationPending). You may need to move your actual work to yet another async delegate (or maybe better yet, submit the work to the ThreadPool), and have your main worker thread poll until this inner worker thread triggers a wait state, OR it detects CancellationPending.

http://msdn.microsoft.com/en-us/library/system.componentmodel.backgroundworker.cancelasync.aspx

http://www.codeproject.com/KB/cpp/BackgroundWorker_Threads.aspx

Do I have to close running BackgroundWorkers when user closes form?

Closing a Form does not stop all background workers started by that form.

When the entire application ends it will stop all background threads.

Closing the main form (unless you have modified the Main method to do something else) will end the entire application.

Each question you referenced is correct for what it says. If you close the main form, then the entire application will end and the background worker will be closed on its own. If the form that is closing isn't the main form, but some other form, and you want the background worker that it starts to be stopped, then you will need to do so yourself.

It's also worth noting that the second link that you have provided asks for something a bit more complex. It's clear in that post that closing the form (if it's the main form) will stop execution of the background thread. What the OP is trying to do there is to tell the background thread, "hey, it's time to finish up, we're done here" and then have the form wait until that background thread can finish cleaning things up nicely, rather than just exiting and forcibly aborting the thread while it's in the middle of doing something.

How to properly handle form closing when using background workers?

The exceptions you mentioned do not have any connection to BackgroundWorker, other than the fact that one thread (the worker) tries to access controls which have been disposed by another thread (the UI).

The solution I would use is to attach an event handler to the Form.FormClosed event to set a flag that tells you the UI has been torn down. Then, then RunWorkerCompleted handle will check to see if the UI has been torn down before trying to do anything with the form.

While this approach will probably work more reliably than checking IsDisposed if you are not disposing the form explicitly, it does not provide a 100% guarantee that the form will not be closed and/or disposed just after the cleanup code has checked the flag and found that it is still there. This is the race condition you yourself mention.

To eliminate this race condition, you will need to synchronize, for example like this:

// set this to new object() in the constructor
public object CloseMonitor { get; private set; }

public bool HasBeenClosed { get; private set; }

private void Form1_FormClosed(object sender, FormClosedEventArgs e) {
lock (this.CloseMonitor) {
this.HasBeenClosed = true;
// other code
}
}

and for the worker:

worker.RunWorkerCompleted += (sender, args) => {
lock (form.CloseMonitor) {
if (form.HasBeenClosed) {
// maybe special code for this case
}
else {
cleanup();
// and other code
}
}
};

The Form.FormClosing event will also work fine for this purpose, you can use whichever of the two is more convenient if it makes a difference.

Note that, the way this code is written, both event handlers will be scheduled for execution on the UI thread (this is because WinForms components use a single-threaded apartment model) so you would actually not be affected by a race condition. However, if you decide to spawn more threads in the future you might expose the race condition unless you do use locking. In practice I have seen this happen quite often, so I suggest synchronizing anyway to be future-proof. Performance will not be affected as the sync only happens once.

Wait for BackgroundWorker finish, if running, at FormClosing time

No need to make it so complex, just have a class level variable

bool quitRequestedWhileWorkerBusy=false;

If the user tried to close the form, in the form closing event check if the worker isbusy, cancel the event and set quitRequestedWhileWorkerBusy=true

In your worker completed event, if(quitRequestedWhileWorkerBusy) this.Close();



Related Topics



Leave a reply



Submit