深入理解 SynchronizationContext
深入理解 SynchronizationContext
SynchronizationContext(后续以SC简称) 是什么?
1.1 概念
在 .NET 框架的多线程程序中,往往很多时间需要将一个线程工作单元或上下文,传递给另一个线程。我们都知道的是 Windows 上的程序是以 消息循环为中心的,这个如何理解呢?
每一个 window 窗体都有一个与之关联的 Window Procedure,这个是一个用来处理所有消息发送或发送到类的给所有消息的函数。窗体的所有UI显示和显示都取决于 Window Procedure 对这些消息的响应。
SynchronizationContext 主要提供了一下三方面的功能:
1) 提供了一种把工作单元 添加到 上下文的队列中的方法。
2) 每一个线程 都有 一个 “current” 的 上下文。
3) 它保存着未完成异步操作数的计数,这个数量 随着 当前的 SC 被捕获,或被夺取时增加,当捕获的 SC 用于将完成通知排队发送到该上下文时,则减少。
// 重要的 SynchronizationContext APIClass
{
// Dispather work to the context.
void Post(); // Asynchronously
void send(); // Synchronously
// Keep track of the number of asynchronous operations.
void OperationStarted();
void OperationCompleted();
// Each thread has a current context.
// If "Current" is null, then the thread's current context is
// "new SynchronizationContext()", by convention.
static SynchronizationContext Current{get;}
static void SetSynchronizationContext(SynchronizationContext);
}
1.2 SynchronizationContext 的实现
1)WindowsFormsSynchronizationContext (System.Windows.Forms.dll)
1,Use ISynchronizeInvoke on UI Control,用来将委托传递 给 win32 message loop
2,每一个 UI 线程 都会创建一个 WindowsFormsSynchronizationContext
3,WindowsFormsSynchronizationContext 的上下文是一个 单一的UI 线程
2)DispatcherSynchronizationContext(WindowsBase.dll: System.Windows.Threading)
1,以 “Normal” 优先级的委托 传递给 UI 线程。
2,所有排队到 DispatcherSynchronizationContext 的委托都是由 特定的UI线程 按照他们排队的顺序 依次执行,一次执行一个。
3,DispatcherSynchronizationContext 的上下文是一个 单一的 UI 线程
3)Default(ThreadPool) SynchronizationContext(mscorlib.dll: System.Threading)
1,默认的 SynchronizationContext 是一个默认构造函数的 SynchronizationContext 对象,按照惯例,如果一个线程 当前的 SynchronizationContext 是 null,那么它会 隐式的 含有一个 默认的 SynchronizationContext。
2,默认 SynchronizationContext 将它的异步委托 添加到 线程池 队列,但是 在调用的线程上执行它的同步委托。因此,它的上下文 涵盖了 所有的线程池的线程 以及 调用它的线程。上下文 “借用” 调用它的线程,然后把它们带入到上下文中 直到委托结束。从某种意义上来说,默认上下文可能包含当前进程中的任何线程。
3,默认 SynchronizationContext 是应用在 线程池中的线程的除非是被 ASP.NET 托管的代码,默认的 SynchronizationContext 也隐式应用于显式的子线程中除非子线程设置了自己的 SynchronizationContext。因此,UI 的应用一般都有两个 SynchronizationContext
, UI 的 SynchronizationContext cover UI thread, default SynchronizationContext
cover ThreadPool thread。
图1 是一个典型比如 WPF 程序,调用 Dispatcher.Invoke
或 Dispatcher.BeginInvoke
时Context 转换的一个图。
private void On_Time_Elapsed(object sender, EventArgs e)
{
Dispatcher.Invoke(()=>{
_displayTextBlock.Text = "Show Here.";
});
}
图1
图2 是 WPF 程序中,Dispatcher.Invoke 中又新开了线程池的线程执行的例子。
private void On_Time_Elapsed(object sender, EventArgs e){
Dispatcher.Invoke(()=>{
Task.Run(()=>{
// Do Something here.
});
_displayTextBlock.Text = "1111";
});
}
图2
各个不同实现的 SynchronizationContext 的区别
Specific Thread Used to Execute Delegates | Exclusive (Delegates Execute One at a Time) | Ordered (Delegates Execute in Queue Order) | Send May Invoke Delegate Directly | Post May Invoke Delegate Directly | |
---|---|---|---|---|---|
Windows Forms | Yes | Yes | Yes | If called from UI thread | Never |
WPF/Silverlight | Yes | Yes | Yes | If called from UI thread | Never |
Default | No | No | No | Always | Never |
ASP.NET | No | Yes | No | Always | Always |