views:

194

answers:

4

From my understanding of .NET, if I use a BackgroundWorker and have an event handler for RunWorkerCompleted, the event handler will run on the same thread in which RunWorkerAsync was called. If instead I use BeginInvoke on a delegate to run a method asynchronously, and pass an AsyncCallback parameter to BeginInvoke, is there any way I can specify that the callback runs on the same thread that called BeginInvoke -- or for that matter any arbitrary thread? From my understanding the callback runs on the next available thread from the thread pool. That's fine, but is there a way I can run code in an AsyncCallback on any thread I want? I do know you can use BeginInvoke on a form or control and make code within the callback run on the thread that created the UI element. But what about if I want to run code on a non-UI thread with no forms or controls?

+4  A: 

On the thread you want to use as the target for your async operation, the CurrentDispatcher Property is a System.Threading.Dispatcher object that can be used to force a callback to execute on that thread.

This is the base class that the Control class uses to implement BeginInvoke.

Questions have come up about using this with Windows forms. I don't think this will be a problem, although if you have a form, then form.BeginInvoke is a better choice. It appears that both the form and WPF use the same base class for handling invoke. http://msdn.microsoft.com/en-us/library/system.threading.synchronizationcontext.aspx

John Knoeller
+1 for the CurrentDispatcher property...
dboarman
System.Windows.Threading.Dispatcher is WPF specific and doesn't have anything to do with the thread where the AsyncCallback of a Delegate.BeginInvoke is called.
SelflessCoder
@Jeff: it provides an alternate BeginInvoke method to allow targeting of the callback. As far as I can tell, this is what he really wants and just muddled his terminology while asking the question.
John Knoeller
@John: Yes I probably did muddle my terminology. I am going to edit my question. I think your answer answers my question. If I want to execute code in a callback on a specific thread, I can pass along to it the Dispatcher of the thread and call BeginInvoke on it. Thanks.
YWE
@John: it appears you're referring to `System.Windows.Threading.Dispatcher`, which appears to be specific to WPF. Can it be used with Windows Forms?
John Saunders
The Dispatcher is available in .NET 3
John Knoeller
@John: For a thread that has a Windows Form, you can use Form.BeginInvoke instead. (although I suspect that CurrentDispatcher on a Windows Forms owning thread will give you the same object that Form.BeginInvoke uses, the documentation implies this).
John Knoeller
@John: a citation, or some research using Reflector, would be more valuable than a belief that they are the same.
John Saunders
@John: check the link I appended. They are derived from the same base class.
John Knoeller
`System.Windows.Threading.DispatcherSynchronizationContext` is derived from `System.Threading.SynchronizationContext. This does not necessarily imply that `System.Windows.Threading.Dispatcher` uses `DispatcherSynchronizationContext`.
John Saunders
A: 

The thread will always be a thread pool thread, and will never be a UI thread.

BTW, C# has no BackgroundWorker class. .NET does.

John Saunders
Thanks. I didn't mean to imply BackgroundWorker was C# specific. I took that out.
YWE
A: 

I did a search and I ended up on Jon Skeet's site. It is very informative about how the threading works with asynchronous delegates and callbacks. I would highly recommend this read.

dboarman
+1  A: 

Delegate.BeginInvoke will always execute the delegate in the ThreadPool and the AsyncCallback is called on the same thread that executed the delegate.

Your only choice is to re-invoke the callback on your specific thread:

AsyncCallback = delegate (IAsyncResult ar)
{
    wathever.BeginInvoke(delegate
    {
        // Do your stuff...
    };
};
SelflessCoder
Do you mean that the AsyncCallback is called on the same thread that called BeginInvoke? This seems contrary to what I understand from the MSDN documentation article entitled "Calling Synchronous Methods Asynchronously" (http://msdn.microsoft.com/en-us/library/2e08f6yc.aspx) where it says "If the thread that initiates the asynchronous call does not need to be the thread that processes the results, you can execute a callback method when the call completes."
YWE
No, I meant that when you call Delegate.BeginInvoke from thread A, this delegate is executed on a thread B in the ThreadPool and then the AsyncCallback is called on thread B.
SelflessCoder
True. I just verified it. I don't think they make that clear in the MSDN documentation.
YWE