响应性地检查两个队列而不锁定CPU

responsively checking two queues without pegging CPU

本文关键字:队列 两个 CPU 锁定 检查 响应      更新时间:2023-10-16

我有一个线程池系统,它使用消息传递来组织事件,我还使用Windows API,它也做一些消息传递。因此,本质上我需要使用在不阻塞的情况下检查消息存在的功能。如果我在检查任一队列时阻止(如果我使用GetMessage,我认为它会阻止(,我可能会错过另一个队列上的任何传入消息。

我知道的第一个解决方案是在我对两个队列进行窥视的循环中,在某个地方Sleep几毫秒。

我可以想到的另一种方法是有一个额外的线程,这样我现在就可以为正在收听的每个循环都有一个线程。我让它不负责运行windows消息循环之外的任何事情,然后用它来处理任何事件,并将其转发到我自己的消息队列中,以便处理该事件。但如果Windows专门将我感兴趣的消息发送到原始线程,这将不起作用。

还有其他好的解决方案吗?

您的要求有点不清楚,但我同意Windows消息队列很尴尬,因为只有一个线程可以等待它们。Windows将窗口绑定到线程,只有创建窗口的线程才能与之交互

如果您的线程池中有包含要处理的工作的用户定义消息,我建议您完全按照问题中的建议执行-使用一个线程处理所有Windows消息,(GetMessage((循环(,重新排队进入线程池输入队列的任何工作,并使用通常的翻译/调度机制处理"正常"Windows消息。

如果你需要更多帮助,你能更清楚地描述Windows消息和/或工作对象在你的系统中的流动吗?线程池的工作从哪里来以及如何传输还不清楚(如果被迫使用WMQ,我通常会在wParam/lParam中发布消息引用,但你的系统呢?(。

Rgds,Martin

通常情况下,线程池不会参与Windows消息循环,并且在没有工作的情况下无限期阻塞不仅是工作线程所允许的,甚至是所希望的

实现线程池的最优雅的方法是使用完成端口,该线程池可以通过某种队列接收消息,这会自动使所有CPU核心保持繁忙,而且效率非常高

具有null句柄的CreateIoCompletionPort将创建一个完成端口并返回句柄。作为NumberOfConcurrentThreads传递零告诉操作系统保持尽可能多的线程运行,只要有可用的内核。

创建任意数量的工作线程(比您的核心多出几个(,并使用第一次调用返回的句柄创建CreateIoCompletionPort。这将把工作进程绑定到这个完成端口。现在在每个工作进程上调用GetQueuedCompletionStatusINFINITE超时,这将不确定地阻止它们。

制作一个struct,它的第一个成员是OVERLAPPED,加上你想作为任务传递的任何数据(一些指向数据的指针,或任何东西(。

对于每个任务,设置一个消息结构,并将PostQueuedCompletionStatus设置为完成端口句柄。在应用程序退出时,发布null。您可以使用dwNumberOfBytesTransferred字段(和完成键(来传递一些附加信息。

现在,Windows将为您发布的每条消息唤醒一个线程,按后进先出的顺序,直到可用的内核数量。如果其中一个工作线程阻塞了IO,Windows将为另一个任务唤醒另一个工作进程(只要有工作要做,就让CPU保持忙碌(。

完成任务后,返回GetQueuedCompletionStatus

一种优雅地终止所有工作程序的方法是传递"传输的零字节",并让工作程序重新发布事件,如果遇到这种情况,则退出。

我不是windows队列方面的专家,但我几乎可以肯定,必须有一种异步事件驱动的消息传递机制。