消息循环是否在 UI 线程上执行?

Does message loop execute on UI thread?

我对 winforms 中消息循环的工作方式感到很困惑。我正在处理 windows 表单,我在调用 Application.Run(myform) 时知道,因此它将创建一个消息队列和消息循环,然后显示我的表单并开始在消息队列中检索消息以进行调度。

我阅读了一些主题,但仍然不明白消息循环在幕后是如何工作的,UI Thread both running message pump AND executing code? and How does the message loop use threads?

我的问题是:消息循环是否会在 UI 线程上 运行。如果是,为什么它不阻塞 UI 线程?

如果问题不清楚,请告诉我,对不起,因为我的英语不好。

Does the message loop run on the UI thread?

是的。确实如此。

If yes why it do not block UI thread?

您应该将消息循环视为无限循环:它永远保持 运行ning。每当队列中有要处理的消息时,它就会拾取并执行它。这可以是一个被点击的按钮。那时按钮会收到有关事件的通知,并且它将 运行 与其关联的代码,例如您的 button_Click 事件处理程序。如果将 Thread.Sleep(10000) 放入其中,您会注意到它会在睡眠期间(10 秒)阻塞整个应用程序。您无法调整大小、重绘或执行任何其他操作,因为消息循环也被阻塞了。事件处理程序结束后,它将继续从队列中获取下一条消息。

可以使用此示例代码大致解释消息循环:

Message message;
while (PeekMessage(out message))
    ProcessMessage(messae);

是的,这 "blocks" 线程。线程将始终等待消息出现(当消息准备好时 PeekMessage 应该 return)或处理消息。

重要的是要知道这个是不会阻挡UI的魔法。 UI 需要响应的任何内容都作为消息处理。

非常重要的部分是为了避免阻塞 UI,无论 ProcessMessage 处理单个消息做什么 都不应花费太长时间.

如果用户单击按钮,这将作为消息处理。作为处理该消息的一部分,您的 事件处理程序将被调用。如果那个事件处理程序开始做一些冗长的事情,你就不会 return 回到消息循环,因此当你的按钮单击事件处理程序是 运行.

时它会停止处理消息

所以是的,消息循环在 UI 线程上运行。是的,它也阻塞了 UI 线程 ,但它保持 运行 的事实意味着它没有阻塞 UI.


受评论的启发,我认为我应该 post 一个解释循环工作原理的类比。

想想当地的熟食店供应食物。有些食物是现成的,只需要卖给消费者,有些食物必须按需准备。

这家熟食店有几个典型的操作:

  1. 必须点餐
  2. 食物必须准备好,或者取来
  3. 必须将食物提供给消费者

现在,考虑一家只有 1 个人在桌子后面的熟食店。

此人为每个消费者执行这三个操作。显然,如果一个消费者点了必须当场准备的食物,其他消费者将不得不等待。

另一方面,如果可以将这些订单交给厨师,即接单员工的同事,那么接单速度会快得多。

在Windows中,消息循环是这个接单员工,而且只有他。

作为处理订单(消息)的一部分,这个人必须去检查其他人,然后等待,然后再将食物(结果)送回给消费者。因此,任何冗长的处理都会减慢此队列的处理速度。

另一方面,如果 "someone else" 只是说,你回到队列并告诉消费者他会在食物准备好时拿到食物,那么队列就会移动,即使现在有人在等他们的食物

这是为了保持 UI 响应而引入的典型线程或异步处理。