views:

448

answers:

1

My C# application has several background workers. Sometimes one background worker will fire off another. When the first background worker completes and the RunWorkerCompleted event is fired, on which thread will that event fire, the UI or the first background worker from which RunWorkerAsync was called? I am using Microsoft Visual C# 2008 Express Edition. Any thoughts or suggestions you may have would be appreciated. Thanks.

+3  A: 

If the BackgroundWorker was created from the UI thread, then the RunWorkerCompleted event will also be raised on the UI thread.

If it was created from a background thread, the event will be raised on an undefined background thread (not necessarily the same thread, unless you're using a custom SynchronizationContext).

Interestingly, this doesn't seem to be all that well-documented on MSDN. The best reference I was able to find was here:

The preferred way to implement multithreading in your application is to use the BackgroundWorker component. The BackgroundWorker component uses an event-driven model for multithreading. The background thread runs your DoWork event handler, and the thread that creates your controls runs your ProgressChanged and RunWorkerCompleted event handlers. You can call your controls from your ProgressChanged and RunWorkerCompleted event handlers.

Aaronaught
Would this be where the control was instantiated? All of my background workers are instantiated (presumably) from the UI thread in the default `InitializeComponent()` function.
Jim Fell
@Jim: Yes, slightly poor wording on the original take; it's actually the thread that created the `BackgroundWorker` that will receive the events, and you must call `RunWorkerAsync` from the same thread. For sanity purposes, that should generally be the UI thread.
Aaronaught
This isn't correct. It will only get raised on the UI thread if the UI thread created the BGW instance. If a thread created the BGW then it will be raised on an arbitrary threadpool thread.
Hans Passant
@Hans: What is the difference between what you said and what I said?
Aaronaught
"will be raised on the same thread", not the case if it wasn't created on the UI thread. Marshaling a call to an arbitrary thread is not possible, only the UI thread has the required plumbing. A WindowsFormsSynchronizationContext or DispatcherSynchronizationContext provider is required, the default provider (SynchronizationContext) makes callbacks on a threadpool thread.
Hans Passant
@Hans: Alright, I've made this more clear. As long as we're nitpicking, it doesn't *have* to be the UI thread; you can create your own `SynchronizationContext` that *does* synchronize.
Aaronaught