Win32 API GetMessage() 的 "blocking" 行为是如何实现的?

How is the "blocking" behavior of Win32 API GetMessage() implemented?

根据 hereGetMessage() 是一个阻塞调用,它不会 return 直到可以从消息队列中检索消息。

那么,这种阻塞行为是如何实现的?

是否 GetMessage() 使用某种 自旋锁 以便 UI 线程只是 忙等待 消息队列中出现新消息?如果是这样,我想当 UI 应用程序 运行ning 时,至少我的 CPU 内核应该有一个高使用率。但我没有看到这种情况发生。那么它是如何工作的呢?

加 1

感谢评论中的提示。自旋锁旨在降低线程上下文切换的成本。它不应该在这里使用。我还考虑过这里可能使用了一些事件范例。但是如果是事件驱动的话,这个事件模型是怎么工作的呢?

我的猜测是这样的:

而且我想也许其他一些事情也是基于定时器中断的,比如线程上下文切换。

添加 2

基于目前的回复。 UI 线程等待某个事件对象。但是由于 UI 线程正在等待某事,它 未激活 并且它自己还不能做任何事情。而事件对象只是一些被动状态信息。所以必须其他人在事件状态改变时唤醒线程。我认为它应该是线程调度程序。并且线程调度器可能被定时器中断脉冲

线程调度程序将定期检查 事件 状态并唤醒线程并在必要时将消息放入其队列中。

我对整个画面的看法是否正确?

加 3

还有一个问题:谁修改了事件对象的状态?根据here,似乎事件只是一些可以修改的数据结构任何活跃。我认为线程调度程序只是使用线程和事件之间的关系来决定哪个线程 运行 或不

当一个线程被安排到 运行 时,它的所有要求都应该已经满足。例如一条消息应该在之前它等待的事件被引发。这是合理的,否则可能为时已晚。 (感谢 RbMm 的评论。)

添加 4

在 JDK 中,LinkedBlockingDeque 类型也提供了与 take() 方法类似的阻塞行为。

Retrieves and removes the head of the queue represented by this deque (in other words, the first element of this deque), waiting if necessary until an element becomes available.

.NET 对应的是 BlockingCollection< T > type. A thread 来讨论它。

这是关于 how to implement a blocking queue in C# 的帖子。

确切的实施是内部的,没有记录。

Windows 中的大多数 window 管理器都是在内核模式下实现的。 GetMessage 也不例外。它等待 event object in kernel mode. When a thread is waiting on an event (or any other kernel-based synchronization object),它不使用任何 CPU 时间,因为它不会安排到 运行,直到等待满足。

当消息发布到等待线程的消息队列时,或者另一个线程向属于等待线程的 window 发送消息,或者等待线程中的计时器触发,或者 window 在等待线程中准备好进行绘制,事件发出信号,线程唤醒,并且 GetMessage() 相应地执行操作,无论是 return 向调用者发送消息,还是分派直接向目标 window 过程发送消息,然后返回等待事件。

如果比较 WaitForMultipleObjects 和 MsgWaitForMultipleObjects:

中可以等待的最大对象数,您可以看到实现泄漏到 public API

The maximum number of object handles is MAXIMUM_WAIT_OBJECTS.

The maximum number of object handles is MAXIMUM_WAIT_OBJECTS minus one.