2012-07-10 49 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