何时在 UI 应用程序中调用 SynchronizationContext.SetSynchronizationContext()?
我正在学习 SynchronizationContext
类。我试图了解在 WinForm/WPF 应用程序上下文中调用 SynchronizationContext.SetSynchronizationContext()
的常见使用场景。设置线程的 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();
});
}
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();
});
}
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
一般来说,您应该将其留给特定的 UI 类库来正确设置。 Winforms 自动安装 WindowsFormsSynchronizationContext 实例,WPF 安装 DispatcherSynchronizationContext,ASP.NET 安装 AspNetSynchronizationContext,Store 应用程序安装 WinRTSynchronizationContext,等等。高度特定的同步提供程序,根据 UI 线程调度事件的方式进行调整。
这些应用程序环境使用其主线程的方式有一些特殊之处。它们都实现了调度程序循环并使用线程安全队列来接收通知。在Windows GUI编程中一般称为“消息循环”。这是生产者/消费者问题的通用解决方案,其中调度程序循环实现消费者。
为工作线程创建您自己的同步提供程序首先要求此类线程实现相同的机制。换句话说,您将需要一个线程安全的队列,例如 ConcurrentQueue,并且需要编写线程来从队列中检索通知并执行它们。委托对象将是一个不错的选择。现在,实现 Post 方法不会有任何问题,只需将 SendOrPostCallback 委托添加到队列中即可。实现 Send 方法需要额外的工作,线程需要发回信号表明委托已被检索并执行。所以队列对象还需要一个AutoResetEvent。
请注意您的线程现在如何不再成为普遍有用的线程,它因必须分派这些通知而陷入困境。以及现有的同步提供程序如何完成所有这一切。因此,如果您的应用程序是 Winforms 应用程序,那么您不妨使用虚拟的不可见表单在工作线程上调用 Application.Run() 。您将自动免费获得其同步提供程序。
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.
2011 年 2 月号的 MSDN 杂志有一篇 google 文章讨论了 SynchronizationContexts 及其在 .NET 领域的各种实现。
http://msdn.microsoft.com/en-us/magazine/gg598924.aspx
对我来说,它确实帮助消除了对该问题的一些困惑。一般来说,正如 Hans 所说,在 WinForms/WPF 应用程序中,您不需要也不应该使用
SetSynchronizationContext()
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()