9

我正在学习这SynchronizationContext门课。我试图了解SynchronizationContext.SetSynchronizationContext()在 WinForm/WPF 应用程序的上下文中调用的常见使用场景是什么。SynchronizationContext设置线程的 是什么意思?我应该什么时候做,为什么?另外,如果我设置它,我应该在某个时候取消它吗?

编辑:

在他的回答中,@Hans Passant 问我为什么要考虑SetSynchronizationContext()。我的想法是在工作线程上设置上下文,以便在该线程上运行的代码将具有要使用的上下文。

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

    });
}
4

2 回答 2

16

通常,您应该将其留给特定的 UI 类库来正确设置。Winforms 自动安装 WindowsFormsSynchronizationContext 实例,WPF 安装 DispatcherSynchronizationContext,ASP.NET 安装 AspNetSynchronizationContext,应用商店应用安装 WinRTSynchronizationContext 等等。高度特定的同步提供程序,已针对 UI 线程调度事件的方式进行了调整。

这些应用程序环境使用其主线程的方式有些特别。它们都实现了调度程序循环并使用线程安全队列来接收通知。在 Windows GUI 编程中通常称为“消息循环”。这是生产者/消费者问题的通用解决方案,调度程序循环实现消费者。

为工作线程创建自己的同步提供程序首先需要这样的线程实现相同的机制。换句话说,您将需要一个线程安全队列,例如 ConcurrentQueue,并且需要编写线程以从队列中检索通知并执行它们。委托对象将是一个不错的选择。您现在可以毫无问题地实现 Post 方法,只需将 SendOrPostCallback 委托添加到队列中即可。实现 Send 方法需要额外的工作,线程需要返回信号,表明已检索并执行了委托。所以队列对象也需要一个AutoResetEvent。

请注意您的线程现在如何不再成为一个普遍有用的线程,它因不得不发送这些通知而陷入困境。以及现有的同步提供者是如何做到这一切的。因此,如果您的应用程序是 Winforms 应用程序,那么您不妨在工作线程上使用虚拟的不可见表单调用 Application.Run()。您将自动免费获得其同步提供程序。

于 2011-01-11T14:51:33.327 回答
2

2011 年 2 月的 MSDN 杂志有一篇谷歌文章讨论了 SynchronizationContexts 及其在 .NET 世界中的各种实现。

http://msdn.microsoft.com/en-us/magazine/gg598924.aspx

对我来说,这确实有助于消除对这个问题的一些困惑。一般来说,正如 Hans 所说,在 WinForms/WPF 应用程序中,您不需要也不应该使用SetSynchronizationContext()

于 2011-08-11T13:45:54.900 回答