Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to stop BackgroundWorker on Form's Closing event?

I have a form that spawns a BackgroundWorker, that should update form's own textbox (on main thread), hence Invoke((Action) (...)); call.
If in HandleClosingEvent I just do bgWorker.CancelAsync() then I get ObjectDisposedException on Invoke(...) call, understandably. But if I sit in HandleClosingEvent and wait for bgWorker to be done, than .Invoke(...) never returns, also understandably.

Any ideas how do I close this app without getting the exception, or the deadlock?

Following are 3 relevant methods of the simple Form1 class:

    public Form1() {         InitializeComponent();         Closing += HandleClosingEvent;         this.bgWorker.RunWorkerAsync();     }      private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e) {         while (!this.bgWorker.CancellationPending) {             Invoke((Action) (() => { this.textBox1.Text = Environment.TickCount.ToString(); }));         }     }      private void HandleClosingEvent(object sender, CancelEventArgs e) {         this.bgWorker.CancelAsync();         /////// while (this.bgWorker.CancellationPending) {} // deadlock     } 
like image 965
THX-1138 Avatar asked Nov 13 '09 19:11

THX-1138


People also ask

How to stop formclosing when backgroundworker is busy?

In the FormClosing event of the main application wait until the IsBusy property of the BackgroundWorker becomes FALSE. A better implementation is to cancel the form closing and to start a custom timer which checks every N milliseconds the IsBusy property.

How do I add a form closing event to a form?

On top of the Properties window, click the Events icon. Double-click the FormClosing event. Visual C# creates an empty event handler method and adds it to your code automatically. If your form’s name was Form1 (which is the default form name) you should find a new method called Form1_FormClosing in your code.

Why does my backgroundworker take a long time to cancel?

If your BackgroundWorker thread takes a while to cancel, you might think about checking for cancel more often. If the form has hooked up some event handlers to the BackgroundWorker thread, you cannot let it close before the BackgroundWorker is done; otherwise the BackgroundWorker will be calling into an object that is in an unknown state.

How do I Close a form in Visual Studio Code?

Double-click the FormClosing event. Visual C# creates an empty event handler method and adds it to your code automatically. If your form’s name was Form1 (which is the default form name) you should find a new method called Form1_FormClosing in your code.


2 Answers

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... } 
like image 122
Hans Passant Avatar answered Sep 30 '22 16:09

Hans Passant


I've found another way. If you have more backgroundWorkers you can make:

List<Thread> bgWorkersThreads  = new List<Thread>(); 

and in every backgroundWorker's DoWork method make:

bgWorkesThreads.Add(Thread.CurrentThread); 

Arter that you can use:

foreach (Thread thread in this.bgWorkersThreads)  {      thread.Abort();     } 

I used this in Word Add-in in Control, which i use in CustomTaskPane. If someone close the document or application earlier then all my backgroundWorkes finishes their work, it raises some COM Exception(I don't remember exatly which).CancelAsync() doesn't work.

But with this, I can close all threads which are used by backgroundworkers Immediately in DocumentBeforeClose event and my problem is solved.

like image 35
Bronix Avatar answered Sep 30 '22 17:09

Bronix