【问题标题】:Dispatcher - How does it work?调度员 - 它是如何工作的?
【发布时间】:2011-12-19 13:23:42
【问题描述】:

在阅读了Dispatcher 类的文档后,我意识到它也可以用于非 UI 的操作队列。

那么Dispatcher 类实际上是如何工作的呢?我知道,它的主要工作是将动作排队到特定线程 - 但它如何将这些动作“发送”到线程?线程如何“获取”这些操作?

我最好的猜测是每个线程都有某种“线程队列”,但我还是不知道。

【问题讨论】:

  • 您是在 WPF 还是 Silverlight 的上下文中询问的?
  • @JoeWhite,两者都不是。您也可以在非 gui 应用程序中使用 Dispatcher
  • @ebb,您可以在没有 GUI 的应用程序中使用它,但这并没有什么意义……有更充分的工具可以做到这一点。调度程序的设计考虑了 UI 场景。
  • @ThomasLevesque,我的问题仍然存在。我知道当在像 WPF 这样的 gui 应用程序中使用时,调度程序将简单地将操作排队到消息队列中。但是,由于普通的“非 gui”线程没有这样的消息循环(至少不是我所知道的),我对它的工作原理很感兴趣。
  • 有趣的问题。显然 Dispatcher 必须使用 Windows 消息队列;但不仅如此,因为 Dispatcher 添加了消息优先级,这不是普通消息队列的一部分。和线程don't even have a message queue unless they create at least one window handle,所以如果你说 Dispatcher 即使在非 UI 应用程序中也能工作是对的,那么它肯定做的不仅仅是包装消息队列。

标签: c# .net windows multithreading


【解决方案1】:

让一个线程开始在另一个线程上执行代码并非易事。问题的症结在于,您不能简单地告诉任何线程在该线程已经启动后开始执行该方法。必须专门设置目标线程才能提前接收此类请求。

通常使用的模式是生产者-消费者。目标线程将围绕一个无限循环旋转,等待消息出现在阻塞队列中。队列被设计为阻塞直到队列中出现一个项目,从而防止目标线程不必要地消耗 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 类的源代码,它似乎创建了一个“仅消息窗口”,因此也创建了一个消息循环 - 但同样......我完全不确定.
【解决方案2】:

好吧,显然 Dispatcher 队列实现看起来像一个 Win32 消息泵,但它不是(虽然它是 uses the same User32 messages and threading model)。

【讨论】:

    【解决方案3】:

    非常有趣的问题,但是你不需要一个窗口来拥有一个消息队列,这些是独立的概念,你可以通过调用PeekMessage在任何线程上创建一个消息队列。

    For more information take a look at here

    当然,这并不意味着没有窗口的 Dispatcher 有任何用处。我可以假设设计者正在考虑一个独立的 Dispatcher 对象,以便让它处理与应用程序一样多的窗口。

    【讨论】:

      猜你喜欢
      • 2011-06-14
      • 1970-01-01
      • 1970-01-01
      • 2016-12-26
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-01-26
      • 2019-04-22
      相关资源
      最近更新 更多