我正在学习SynchronizationContext
课程。我试图了解在WinForm / WPF应用程序的上下文中调用SynchronizationContext.SetSynchronizationContext()
的常见用法场景。设置线程的SynchronizationContext
是什么意思?我什么时候该做,为什么?另外,如果我设置它,我应该在某个时候取消它吗?
修改:
在他的回答中,@汉斯帕斯特问我为什么在考虑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();
});
}
答案 0 :(得分:14)
您通常应该将其留给特定的UI类库来正确设置它。 Winforms自动安装WindowsFormsSynchronizationContext实例,WPF安装DispatcherSynchronizationContext,ASP.NET安装AspNetSynchronizationContext,Store应用程序安装WinRTSynchronizationContext等。高度特定的同步提供程序,它们调整为UI线程调度事件的方式。
这些应用程序环境使用主线程的方式有一些特别之处。它们都实现了一个调度程序循环,并使用一个线程安全的队列来接收通知。通常称为Windows GUI编程中的“消息循环”。这是生产者/消费者问题的通用解决方案,调度程序循环实现了消费者。
为工作线程创建自己的同步提供程序首先要求这样的线程实现相同的机制。换句话说,您将需要一个线程安全的队列,如ConcurrentQueue,并且需要编写线程以从队列中检索通知并执行它们。委托对象将是一个不错的选择。现在,您将实现Post方法没有问题,只需将SendOrPostCallback委托添加到队列即可。实现Send方法需要额外的工作,线程需要发回信号表示检索并执行了委托。所以队列对象也需要一个AutoResetEvent。
请注意您的线程现在如何停止成为一个通常有用的线程,它因为必须发送这些通知而陷入困境。现有的同步提供商如何完成所有这些工作。因此,如果您的应用程序是Winforms应用程序,那么您也可以使用虚拟不可见形式在工作线程上调用Application.Run()。并且您将自动免费获得其同步提供程序。
答案 1 :(得分:1)
2011年2月刊的MSDN杂志有一篇谷歌文章讨论了SynchronizationContexts及其在.NET领域的各种实现。
http://msdn.microsoft.com/en-us/magazine/gg598924.aspx
对我来说,这确实有助于澄清对这个问题的一些困惑。一般来说,正如汉斯所说,在WinForms / WPF应用程序中,您不需要也不应该使用SetSynchronizationContext()