How to Dispose of a Backgroundworker

Proper way to Dispose of a BackGroundWorker

BackgroundWorker derives from Component. Component implements the IDisposable interface. That in turn makes BackgroundWorker inherit the Dispose() method.

Deriving from Component is a convenience for Windows Forms programmers, they can drop a BGW from the toolbox onto a form. Components in general are somewhat likely to have something to dispose. The Windows Forms designer takes care of this automatically, look in the Designer.cs file for a Form for the "components" field. Its auto-generated Dispose() method calls the Dispose() method for all components.

However, BackgroundWorker doesn't actually have any member that requires disposing. It doesn't override Dispose(). Its base implementation, Component.Dispose(), only makes sure that the component is removed from the "components" collection. And raise the Disposed event. But doesn't otherwise dispose anything.

Long story short: if you dropped a BGW on a form then everything is taken care of automatically, you don't have to help. If you didn't drop it on a form then it isn't an element in a components collection and nothing needs to be done.

You don't have to call Dispose().

C#: Do I need to dispose a BackgroundWorker created at runtime?

Yes, you should dispose of the background worker.

You may find it easier to use ThreadPool.QueueUserWorkItem(...) which doesn't require any clean up afterwards.


Additional detail on why you should always call Dispose():

Although if you look in the BackgroundWorker class it doesn't actually do any thread clean up in it's dispose method, it is still important to call Dispose because of the effect the class has on the garbage collector.

Classes with finalizers are not GCed immediately. They are kept and added to the finalizer queue. The finalizer thread then runs, (which following the standard pattern calls dispose). This means the object will survive into GC generation 1. And gen 1 collections are far rarer than gen 0 collections, so you object sticks around in memory for much longer.

If however you call Dispose(), the object will not be added to the finalization queue, so is free to be garbage collected.

It's not really big problem, but if you are creating a lot of them you'll end up using more memory than necessary. It should really be considered good practise to always call dispose on objects that have a dispose method.

So I suppose, all in all, it's not a 100% hard and fast requirement. Your app won't explode (or even leak memory) if you don't call Dispose(), but in some circumstances it may have negative effects. The background worker was designed for use from as a WinForms component so use it that way, if you have different requirements and don't want to use it as a WinForms component, don't use it, use the correct tool for the job, like the ThreadPool.

Disposal of a Running BackgroundWorker

It depends, we can't see your code. First off, it is pretty unlikely that you can implement CancelAsync() so don't bother with that. Spinning until IsBusy returns false in the Dispose() method is an option, but do beware of deadlock. You'll definitely get one when you implemented an event handler for RunWorkerCompleted. It is unlikely you have one so spinning ought to be okay.

The sane approach is to just let it run. The user will be happy. Some precautions are necessary:

  • The worker thread should still be able to access the properties of the control even if it was disposed. This is not normally a problem, you store the values of simple backing variables, they don't become invalid when the control is disposed. Easy to test btw, but if you are not sure then using a simple class that stores the values that need to be preserved and passing it to RunWorkerAsync() is always safe.

  • You need to deal with the risk of the worker thread being aborted because the program terminated. If that happens just as it is writing the file then the file will get corrupted. You solve this by writing to another file instead. And using File.Replace() to swap it. In general always a strategy you should use when you replace files.

background worker dispose vs thread.abort

Well, actually, you are assigning an infinite task to your BackgroundWorker (this is because while (true) must implement an explicit command that stops the infinite loop like a break statement or a return statement).

Once the method handler is fired (through the invocation of bg.RunWorkerAsync()), it will keep on running no matter what you do.

Unsubscribing the event handler will not stop it, because somewhere over the rainbow the show must go on.

Disposing the BackgroundWorker instance will not stop it either. The BackgroundWorker class derives from Component (which implements the IDisposable interface) and inherits the Dispose() method, but without overriding it. In its base implementation, Component.Dispose() only grants that the component is removed from the components collection and the Disposed event is raised... but the thread being created doesn't get killed.

Keeping your design as it currently is, the only way you can stop the BackgroundWorker is settings its WorkerSupportsCancellation property to true upon creation:

bg = new BackgroundWorker();
bg.WorkerSupportsCancellation = true;

and then calling:

bg.CancelAsync();

when needed. Avoid the Thread.Abort() approach, it's unsafe.

Disposing a background worker

Is it necessary to dispose off the Background Worker after ...

No. The BackgroundWorker does implement the IDisposable interface but only as a blanket feature inherited from Component. It serves no purpose.

If I put this bgWorker.RunWorkerAsync() in timer_elapsed

Doubtful if you should do that at all. But if you do, just create a new Backgroundworker each time.

A Backgroundworker is a relatively 'light' object, it holds no resources. The thread is borrowed from the ThreadPool.

If you are a stickler for principal, you may call Dispose() on the old one before creating a new one. But it won't make much difference.

How to dispose BackgroundWorkers the right way

Frankly, when you stop your windows service - it really doesn't matter. Your win32 process is terminated, so its not strictly necessary to clean up your IDisposables. Any unmanaged resources will have a finalizer that will still run.

That said, it's normal to have a class level background worker that gets disposed when e service class does. Not necessary, but it's always good to be clean.

Waiting for Backgroundworker in Dispose()

Because of this line:

while (_worker != null && _worker.IsBusy)
Application.DoEvents(); // Hack throw worker.RunWorkerCompleted on top of msg queue

Even if the DoWork has finished, your while loop will prevent RunWorkerCompleted to get executed because they are in the same thread (while loop keeps executing.

Change the code like this:

private void AsyncWorker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
if (!e.Cancelled && e.Error == null && !IsDisposed && !IsDisposing)
{
if (!_closing)
{
this.Grid = e.Result as MyGrid;
AttachEventHandlersToGrid();
}
else
{
(e.Result as MyGrid).Dispose(); // Get rid of grid
}
}

// Get rid of worker
_worker.DoWork -= DoActionsOnAsyncWork;
_worker.RunWorkerCompleted -= AsyncWorker_RunWorkerCompleted;
_worker.Dispose();
_worker = null;
if(_closing)
this.Dispose(); //call Dispose again, now you know that worker has finished
}
protected bool HasBackgroundWorkerFinished()
{
if (_worker == null ||
!_worker.IsBusy)
return true;
_worker.CancelAsync();
_closing = true; //this means that worker is busy
return false;
}
protected override void Dispose(bool disposing)
{
bool dispose = true;
if (disposing)
{
dispose = HasBackgroundWorkerFinished();
if (dispose)
{
// Dispose other stuff
}
}
if(dispose) //don't dispose if worker didn't finish
base.Dispose(disposing);
}

Set the _worker to accept canceling and add this code multiple times

if (_worker.CancellationPending)
{
e.Cancel = true;
return;
}

to your DoWork code between all major code parts

Dispose of dialogwindow in backgroundworker

Firstly, ShowDialog() will prevent the rest of the code executing until the dialog is closed - which you are never doing.

Even when it does close, it will evaluate the while loop (which will most likely be false so skipped) and then your backgroundworker will be finished.

If all you are doing is showing a dialog then I would just do this on the main thread, and have your loading process on the background worker..

  1. Fire background worker (which does loading code)
  2. Show your loading dialog
  3. On BackgroundWorkerCompleted event, close your loading dialog

Try to get all your UI elements in the main UI thread.

Hope that helps

EDIT:

Based on your comment...

public partial class MainForm:Form
{
LoadingScreen ls;

public MainForm()
{
}

public void StartLoad()
{
ls = new LoadingScreen(this.timerStart);
backgroundWorker.RunWorkerAsync();
ls.Show();
}

void backgroundWorkerDoWork(object sender, DoWorkEventArgs e)
{
//Loading code goes here
}

void BackgroundWorkerMainRunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
if(ls != null)
ls.Close();
}
}


Related Topics



Leave a reply



Submit