When to call SynchronizationContext.SetSynchronizationContext() in a UI application?
Asked Answered
S

2

10

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();

    });
}
Symmetrize answered 11/1, 2011 at 14:46 Comment(0)
F
17

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.

Fiery answered 11/1, 2011 at 14:51 Comment(3)
does my update change your answer? Do you think setting SynchronizationContext on a worker thread like that should be avoided as well?Symmetrize
I'd really like to hear what you think about this...ThanksSymmetrize
Hans, can you help me with #13500530 - I found I had to use SetSync because it wasn't being set by Send/Post in my class.Bathroom
R
3

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()

Runny answered 11/8, 2011 at 13:45 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.