I'm learning about the SynchronizationContext
class. I'm trying to understand what are the common usage scenarios for calling SynchronizationContext.SetSynchronizationContext()
in the context of a WinForm/WPF application. What does it mean to set the SynchronizationContext
of a thread? When should I do it and why? Also, if I set it, should I unset it at some point?
Edit:
In his answer, @Hans Passant asked why I was contemplating SetSynchronizationContext()
. The idea I have is to set the context on a worker thread so that code running on that thread will have a context to use.
private void button3_Click(object sender, EventArgs e)
{
var syncContext = SynchronizationContext.Current;
Task.Factory.StartNew(() =>
{
// Setup the SynchronizationContext on this thread so
// that SomeAsyncComponentThatNeedsACurrentContext
// will have a context when it needs one
if (SynchronizationContext.Current == null)
SynchronizationContext.SetSynchronizationContext(syncContext);
var c = new SomeAsyncComponentThatNeedsACurrentContext();
c.DoSomething();
});
}
SynchronizationContext is a representation of the current environment that our code is running in. That is, in an asynchronous program, when we delegate a unit of work to another thread, we capture the current environment and store it in an instance of SynchronizationContext and place it on Task object.
SynchronizationContext provides us a way to update a UI from a different thread (synchronously via the Send method or asynchronously via the Post method). The last example and this one executes the same. Both doesn't block the UI while it does it jobs.
You should in general leave it up to the specific UI class library to set this correctly. Winforms automatically installs a WindowsFormsSynchronizationContext instance, WPF installs a DispatcherSynchronizationContext, ASP.NET installs a AspNetSynchronizationContext, a Store app installs WinRTSynchronizationContext, etcetera. Highly specific synchronization providers that are tuned to the way the UI thread dispatches events.
There's something special about the way these application environments use their main thread. They all implement a dispatcher loop and use a thread-safe queue to receive notifications. Generally known as the "message loop" in Windows GUI programming. This is a generic solution to the producer/consumer problem, with the dispatcher loop implementing the consumer.
Creating your own synchronization provider for a worker thread first requires that such a thread implements this same mechanism. In other words, you will need a thread-safe queue, like ConcurrentQueue, and the thread needs to be written to retrieve notifications from the queue and execute them. A delegate object would be a good choice. You will now have no problem implementing the Post method, simply add the SendOrPostCallback delegate to the queue. Extra work is required to implement the Send method, the thread needs to signal back that the delegate was retrieved and executed. So the queue object also needs an AutoResetEvent.
Do note how your thread now stops becoming a generally useful thread, it is bogged down by having to dispatch these notifications. And how the existing synchronization providers already do all of this. So if your app is a Winforms app then you might as well call Application.Run() on your worker thread with a dummy invisible form. And you'll automatically get its synchronization provider for free.
The February 2011 issue of MSDN Magazine had a google article discussion SynchronizationContexts and their various implementations across the .NET universe.
http://msdn.microsoft.com/en-us/magazine/gg598924.aspx
For me, it really helped clear up some of the confusion over the issue. In general, as Hans says, in a WinForms/WPF application, you don't need to, and shouldn't, use SetSynchronizationContext()
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With