0

我试图了解MsgWaitForWaitFor功能之间的区别。

1)我知道MsgWaitFor在消息循环下运行,而WaitFor没有?
2)MsgWaitFor对于需要连续接收一系列事件的应用程序,这些功能是否更好?Windows 是否对消息进行排队,以便应用程序不会错过任何事件?假设应用程序想要接收事件A并且B经常发生。应用程序将打开一个线程:

while (1) {
  ret = WaitForMultipleObjects(...); // wait for events A and B
  if (ret == WAIT_OBJECT_0) {
    process_event();
  }
}

问题是,当线程忙于处理时,这意味着它当前没有被WaitForMultipleObjects. 线程如何避免错过事件,直到它回到等待状态?

4

2 回答 2

0

两者MsgWaitForMultipleObjects[Ex]WaitForMultipleObjects[Ex]内部调用相同的api -KeWaitForMultipleObjects

不同的 in -MsgWaitForMultipleObjects[Ex]将事件(在前面,在 0 索引处)添加到对象句柄数组。因为KeWaitForMultipleObjects对最大对象数有限制MAXIMUM_WAIT_OBJECTS,所以同样的限制有 andWaitForMultipleObjects[Ex]MAXIMUM_WAIT_OBJECTS - 1for MsgWaitForMultipleObjects[Ex](因为使用了额外的 +1 事件对象)

仅存在 2 WAIT_TYPE- 要么WaitAll,表示所有指定的对象必须在等待满足之前达到信号状态;或WaitAny,表示任何一个对象必须在等待得到满足之前达到信号状态。

当我们等待对象发出信号时 - 在我们开始等待之前或之后处于信号状态的对象并不重要。无论如何,我们不会错过信号状态。当然,如果我们不手动将对象重置为不发出信号状态。但这已经是程序逻辑的问题,与等待 api 无关

连续的事件序列

这里不存在任何序列。每个对象都可以处于两种状态(有信号或无信号),我们可以等待所有或任何处于信号状态的对象。如果您等待任何 - 首先将发出信号的对象取决于具体情况。

Windows 是否对消息进行排队,以便应用程序不会错过任何事件?

根本没有任何消息。仅存在内部带有DISPATCHER_HEADER(查看wdm.h)的对象。等待 api 检查SignalStateDISPATCHER_HEADER如果它已经设置 - 返回控制(如果我们等待单个对象或任何对象当然)。if not - 插入线程WaitListHead(这是双链表,其中可以是多个线程,等待这个对象,并从win8开始 - WaitCompletionPacket的对象。当对象进入信号状态时(SignalState设置为非零)。系统首先唤醒(SynchronizationEvent)或所有(NotificationEvent,其他对象类型)等待线程WaitListHead(再次基于 waitall 或等待任何)。如果WaitCompletionPacket - 它排队到 iocp

再一次 - 我们没有错过(如果没有再次自行重置对象)

于 2020-05-10T09:59:20.107 回答
0

我试图了解 MsgWaitFor 和 WaitFor 函数之间的区别。

主要区别是MsgWaitForMultipleObjects/MsgWaitForMultipleObjectsEx除了以下对象类型外,还可以等待消息(在消息队列中):

  • 变更通知
  • 控制台输入
  • 事件
  • 内存资源通知
  • 互斥体
  • 过程
  • 信号
  • 线
  • 等待定时器

因此,如果您有一个创建窗口的线程,请使用MsgWaitForMultipleObjectsor MsgWaitForMultipleObjectsEx,而不是WaitForMultipleObjectsEx.

问题是,当线程忙于处理时,这意味着它当前没有被 WaitForMultipleObjects 阻塞。线程如何避免错过事件,直到它回到等待状态?

消息有队列,队列有一个长度(10,000 条发布的消息)。因此,当处理消息太慢时,PostMessage可能会失败并显示ERROR_NOT_ENOUGH_QUOTA. 但是对于接收方来说,你不会错过消息,你可以一一处理排队的消息。

事件对象没有队列,它有两种状态:signalednonsignaled设置已设置的事件没有任何效果。因此,如果这是一个手动重置事件对象,它会一直存在,signaled直到它被函数显式设置为nonsignaled状态ResetEvent。在设置方而不是检查方可能会出现失误。

于 2020-05-12T02:08:41.053 回答