C++ 在不占用CPU的情况下响应性地检查两个队列

C++ 在不占用CPU的情况下响应性地检查两个队列,c++,multithreading,winapi,asynchronous,message-queue,C++,Multithreading,Winapi,Asynchronous,Message Queue,我有一个线程池系统,它使用消息传递来组织事件,我也在使用Windows API,它也做一些消息传递。因此,本质上我需要使用一些函数来检查消息的存在而不阻塞。如果我在检查任一队列时阻塞(如果我使用GetMessage我想它会阻塞),我可能会错过另一个队列上的任何传入消息 我知道的第一个解决方案是在我窥视两个队列的循环过程中,在某处睡眠几毫秒 我能想到的另一种方法是增加一个线程,这样现在我听到的每个循环都有一个线程。我使它不负责执行除运行windows消息循环以外的任何操作,然后使用它来处理任何事件

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

我知道的第一个解决方案是在我窥视两个队列的循环过程中,在某处睡眠几毫秒

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


还有其他好的解决办法吗

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

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

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

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

如果需要更多帮助,能否更清楚地描述Windows消息和/或工作对象在系统中的流动?线程池的工作从何而来以及如何传输并不明显(如果被迫使用WMQ,我通常会在wParam/lParam中发送一个引用的后消息,但是您的系统呢?)

Rgds,
Martin

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

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

如果需要更多帮助,能否更清楚地描述Windows消息和/或工作对象在系统中的流动?线程池的工作从何而来以及如何传输并不明显(如果被迫使用WMQ,我通常会在wParam/lParam中发送一个引用的后消息,但是您的系统呢?)

Rgds,
Martin

通常情况下,Windows消息循环中不会涉及线程池,并且当没有工作时,不仅允许工作线程无限期地阻塞,而且还允许工作线程无限期阻塞

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

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

使用第一次调用返回的句柄创建任意数量的工作线程(比核心多几个)和
CreateIoCompletionPort
。这将把工人绑定到这个完成端口。现在调用
GetQueuedCompletionStatus
,对每个工作进程执行
INFINITE
超时,这将无限地阻止它们

制作一个
struct
,它的第一个成员是重叠的,加上您想要作为任务传递的任何数据(一些指向数据的指针或任何东西)

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

现在Windows将为您发布的每封邮件唤醒一个线程,按照后进先出的顺序,直到可用的内核数为止。如果其中一个工作进程阻塞IO,Windows将唤醒另一个工作进程以执行另一项任务(只要有工作要做,就让CPU保持忙碌)

完成任务后,返回
GetQueuedCompletionStatus


优雅地终止所有工作线程的一种方法是传递“已传输的零字节数”,并让工作线程重新发布事件,如果遇到该事件,则退出。

通常,Windows消息循环中不会涉及线程池,并且在没有工作时无限期阻塞不仅允许工作线程,但是,即使是理想的

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

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

创建任意数量的工作线程(几个mo