CODE: Sequoia

Sunday, October 08, 2006

How to shutdown worker thread on Form closing?

Use BeginInvoke instead of Invoke.

Let's assume you are writing a .NET application which has a progress bar.

  • It starts a worker thread when the application starts.
  • The worker thread does some lengthy work.
  • The worker thread calls OnProgress() delegate whenever some progress happens.

Since you may not call any Control methods from non-UI thread, the implementation of OnProgress would be something like this (Use Control.Invoke):

private void OnProgress(int percent){
  Invoke(new MethodInvoker(delegate(){
    progressBar.Value = percent;
  }));
}

ObjectDisposedException!?

However, you have a problem here. OnProgress() is called from the worker thread which does not know anything about the UI thread. For example, it might be called *after* the Form is closed. If it happens, you get ObjectDisposedException.

How about stopping the worker thread in OnClosed()?

You might want to try stopping the worker thread in Form.OnClosed() so that OnProgress() cannot be called after Form's disposal.

protected override void OnClosed(EventArgs e) {
  // ...
  // cancel worker thread
  // ...
  workerThread.Join();
  base.OnClosed(e);
}

Opps, it's now dead locked.

Unfortunately, the solution is not right. OnClosed() is called from UI thread, and it is blocked at Thread.Join(). While it's blocked, OnProgress() is also blocked because Invoke() requires the UI thread to work. (Remember: The delegate passed to Invoke() is executed by the UI thread.)

So, what should I do?

Use BeginInvoke() instead of Invoke(). BeginInvoke() does not block the caller thread, so the deadlock can be avoided.

How about EndInvoke()?

You might wonder when to call EndInvoke(). If you call EndInvoke(), the caller thread is blocked until the delegate is processed - it's essentially same as Invoke(). Therefore, you have the same deadlock issue again.

Fortunately, you don't have to call EndInvoke(). It's not well documented in MSDN, but it is "officially" true. See the comments of the blog entry below: http://blogs.msdn.com/cbrumme/archive/2003/05/06/51385.aspx

0 Comments:

Post a Comment

<< Home