深入理解 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 |