2012-07-10 77 views
14

我想我需要一些幫助來理解調度隊列瞭解調度隊列

當新工作到達時,它將在調度程序隊列的開始處添加,並且當分派器想要處理工作項時,它將從頭開始移除。

更籠統地說:如果有工作,它會以FIFO方式存儲在隊列中,並在沒有剩餘工作的情況下進行處理。

MSDN文檔here指的是一個loopframe

The Dispatcher processes the work item queue in a loop. The loop is referred to as a frame.

但哪裏是在這種情況下一個循環?對我來說,一個循環就是對某個東西進行迭代的過程,當它到達終點時,它會重新開始。

什麼是frame的概念?根據MSDN文檔,框架是隊列中工作項目的一個重要組成部分?如果這是真的,應該如何使用靜態方法Disptatcher.PushFrame()

而最有趣的問題是是否有任何方法來獲取隊列的當前狀態,特別是隊列中有多少物品。

如果之前調用的方法(以及因此放入Dispatcher隊列中)被執行後立即從隊列中移除或在另一段時間內持續存在,它會保留嗎?

我知道,:-)

+1

第一個問題:爲什麼?爲什麼要使用Dispatcher?通常,分派器只是WPF過程的「消息泵」。它通過WPF UI處理應用程序代碼中的所有消息/事件/命令(例如,鼠標移動,點擊等)。當應用程序Run方法被調用時,它調用PushFrame來啓動該循環。你不能爲同一個線程啓動另一個;而分派器是爲了處理UI工作。 – 2012-07-10 18:23:31

+2

您是否閱讀過[線程模型](http://msdn.microsoft.com/zh-cn/library/ms741870.aspx)? – 2012-07-10 18:24:45

+1

這是生產者 - 消費者問題的標準解決方案:http://en.wikipedia.org/wiki/Producer-consumer_problem – 2012-07-10 18:26:02

回答

22

這麼多的問題還有周圍的Dispatcher很少的文件,所以你必須拆開了一下週圍知道的內部運作。

調度員基本上是執行應用程序的Message Pump工作的東西。有問題的人坐在windows message loop之上。

因此,只能有一個應用程序分派器 - 全球分派器對象可由Application.Current.Dispatcher訪問。其他調度員通過訪問Dispatcher.CurrentDispatcher,根據文檔

其獲取調度當前正在執行的線程,並創建一個新的 調度如果一個尚未與線程關聯是可能的。

但是,在這個新的調度程序上調用Run將被阻塞。

當你做一個Dispatcher.PushFrame,它基本上推送一幀到當前的調度器。任何從DispatcherObject繼承的內容(如DispatcherFrame)都會將其調度程序設置爲當前調度程序。我們可以通過查看它的構造函數來驗證它。

private Dispatcher _dispatcher; 

protected DispatcherObject() 
{ 
    this._dispatcher = Dispatcher.CurrentDispatcher; 
} 

當然,有一個簡單的事件循環是不夠的 - 有些時候,你需要顛覆目前的事件循環迫使其他的工作要做。這就是爲什麼你有一個DispatcherFrame。這實際上構成了事件循環。當你把一幀在調度程序,這是發生了什麼:

while (frame.Continue) 
     { 
      if (!this.GetMessage(ref msg, IntPtr.Zero, 0, 0)) 
      { 
       break; 
      } 
      this.TranslateAndDispatchMessage(ref msg); 
     } 

正是在在調度優先隊列被評爲TranslateAndDispatchMessage,一條消息被取出後。

如果操作需要很長時間才能在調度程序上運行,它會暫時停止事件循環,並且因爲它不響應信號,應用程序似乎會停止響應。

Here's an article它使用框架強制UI通過允許事件循環很快運行來響應。

至於訪問隊列,實際上沒有辦法知道分派器外部的隊列狀態。這是一個內部細節,它沒有暴露是合理的。

+1

非常感謝您的詳細解答(並對延遲抱歉) – 2012-07-16 13:25:54

+1

@Marc沒問題。 :) – Asti 2012-07-16 14:54:28

+6

_「因此,每個應用程序只能有一個Dispatcher。」_。 <=這是不正確的,分派器實例將被綁定在線程上。請參閱Dispatcher.CurrentDispatcher的摘要:_「獲取當前正在執行的線程並創建一個新的線程,如果尚未與線程關聯。」_您可以將Dispatcher想象爲messagepump的擴展,該擴展允許執行代表而不是僅處理消息代碼。 – 2013-08-22 08:19:39