响应检查两个队列而不挂断CPU

时间:2011-07-03 06:44:21

标签: c++ multithreading winapi asynchronous message-queue

我有一个线程池系统,它使用消息传递来组织事件,我也使用Windows API,它也做了一些消息传递。所以基本上我需要使用检查消息是否存在而不阻塞的函数。如果我阻止(如果我使用GetMessage我认为它将阻止)在检查任一队列时,我可能会错过另一个队列上的任何传入消息。

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

我能想到的另一种方法是有一个额外的线程,所以现在我有一个用于我正在收听的每个循环。我不负责除了运行Windows消息循环之外做任何事情,然后使用它来处理和转发任何事件到我自己的消息队列以便处理事件。但是,如果Windows专门将我感兴趣的消息发送到原始线程,这将不起作用。

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

3 个答案:

答案 0 :(得分:1)

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

如果您的用户定义的消息包含要处理到线程池的工作,我建议您完全按照您在问题中的建议 - 使用一个线程来处理所有Windows消息,(GetMessage()循环) ,重新排列任何可以转换到线程池输入队列的工作,并使用通常的Translate / Dispatch机制处理“正常”的Windows消息。

如果您需要更多帮助,是否可以通过系统更清楚地描述Windows消息和/或工作对象的流程?线程池的工作来自何处以及如何传输是不明显的(如果强制使用WMQ,我通常在wParam / lParam中使用postMessage引用,但是你的系统?)。

RGDS, 马丁

答案 1 :(得分:0)

我不是Windows队列的专家,但我几乎肯定必须有一个异步事件驱动机制来传递消息。

答案 2 :(得分:0)

通常情况下,一个线程池不会涉及Windows消息循环,并且在没有工作时无限期地阻塞不仅允许工作线程,甚至理想

实现可以通过某种队列接收消息的线程池的最优雅方式是使用完成端口,该队列自动保持所有CPU核心繁忙,并且作为奖励是非常有效的。

带有 null 句柄的

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

使用第一次调用返回的句柄创建任意数量的工作线程(比核心多一些)和CreateIoCompletionPort 。这将把工人绑在这个完工港口。现在为每个工作人员调用GetQueuedCompletionStatus INFINITE超时,这将无法阻止他们。

创建一个{O}有一个OVERLAPPED作为第一个成员的struct,以及你想要作为任务提交的任何数据(一些指向数据的指针,或任何东西)。

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

现在,Windows将按照后进先出顺序为您发布的每条消息唤醒一个线程,最多可用核心数。如果其中一个工作程序在IO上阻塞,Windows将唤醒另一个工作程序以执行另一项任务(只要有工作要做就保持CPU忙碌)。

完成任务后,请返回GetQueuedCompletionStatus

一种优雅地终止所有工作者的方法是传递“零字节传输”并让工作人员重新发布事件,并在遇到事件时退出。