在閱讀Dispatcher
類的文檔後,我意識到它也可以用於非UI排隊的操作。調度員 - 它是如何工作的?
那麼Dispatcher
類是如何實際工作的?我意識到這一點,主要的工作是將動作排隊到特定的線程 - 但它如何將這些動作「發送」到線程?線程如何「獲取」這些操作?
我最好的猜測是每個線程都有一些「線程隊列」,但是我再也不知道了。
在閱讀Dispatcher
類的文檔後,我意識到它也可以用於非UI排隊的操作。調度員 - 它是如何工作的?
那麼Dispatcher
類是如何實際工作的?我意識到這一點,主要的工作是將動作排隊到特定的線程 - 但它如何將這些動作「發送」到線程?線程如何「獲取」這些操作?
我最好的猜測是每個線程都有一些「線程隊列」,但是我再也不知道了。
好吧,顯然分派器隊列實現看起來像一個Win32消息泵,但它不是(儘管它uses the same User32 messages and threading model)。
讓一個線程開始執行代碼到另一個線程並不是一件簡單的事情。問題的關鍵是你不能簡單地告訴任何線程在該線程已經啓動之後開始執行一個方法。目標線程必須專門設置以提前接收這些請求。
通常使用的模式是生產者 - 消費者。目標線程將圍繞無限循環旋轉,等待消息出現在阻塞隊列中。該隊列被設計爲阻塞,直到項目出現在隊列中,從而防止目標線程不必要地佔用CPU時間。這是一個非常簡單的方法來讓線程接受注入委託來執行。
public class Example
{
private BlockingCollection<Action> queue = new BlockingCollection<Action>();
public Example()
{
new Thread(
() =>
{
while (true)
{
Action action = queue.Take();
action();
}
}).Start();
}
public void ExecuteAsync(Action action)
{
queue.Add(action);
}
}
如今,在UI的情況下,線程它已經運行,以便Dispatcher
類可以簡單地發佈一個特殊的信息,包含委託消息隊列要執行的消息循環。在處理所有繪畫,按鈕點擊等過程中,這個特殊消息也將被UI線程拾取,並且它將開始執行委託。
那麼Dispatcher類是如何實際工作的?我意識到這一點, 它的主要工作是將動作排隊到特定的線程 - 但它如何將這些動作「發送」到線程?
通過將委託排隊到目標線程監視的隊列中。
線程如何「獲取」這些操作?
通過運行監視隊列的無限循環。隊列通常是一種稱爲阻塞隊列的特殊類型,如果隊列爲空,則阻塞消耗線程。
我最好的猜測是每個 線程都有某種「線程隊列」,但是我再也不知道了。
非常接近。除了線程實際上沒有內置隊列用於此目的。它必須手動設置。這就是爲什麼只有專門設計的線程才能接受委託注入。 UI線程以這種方式設置,因爲Application.Run
創建了消息循環。在我的示例中,您將看到我必須使用BlockingCollection
和無限循環才能使其在工作線程上工作。
感謝您的回答! - 我完全理解生產者/消費者等概念。我質疑的是Dispatcher如何/爲什麼在非gui應用程序中工作。目前我正在查看實際的Dispatcher類的源代碼,它似乎創建了一個「僅消息窗口」,因此也是一個消息循環 - 但是再次......我完全不確定。 – ebb 2011-12-19 17:44:26
非常有趣的問題,但你不需要一個窗口有一個消息隊列,這些是不同的概念,你可以在任何線程上創建一個消息隊列,只需調用PeekMessage。
For more information take a look at here
但當然,這並不意味着,沒有窗戶的調度沒有任何用處的。我可以假設設計人員正在考慮一個獨立的Dispatcher對象,以便讓它處理與應用程序一樣多的窗口。
你問在WPF或Silverlight的上下文嗎? – 2011-12-19 13:30:15
@JoeWhite,都不是。您也可以在非gui應用程序中使用「Dispatcher」。 – ebb 2011-12-19 13:31:47
@ebb,你可以在沒有GUI的應用程序中使用它,但它沒有任何意義......有更多的工具可以做到這一點。調度程序*設計時考慮了UI場景。 – 2011-12-19 13:36:45