Winapi 带有WM#U用户不';当MsgWaitForMultipleObjectsEx被用来检查它时,它似乎没有到达

Winapi 带有WM#U用户不';当MsgWaitForMultipleObjectsEx被用来检查它时,它似乎没有到达,winapi,sendmessage,waitformultipleobjects,Winapi,Sendmessage,Waitformultipleobjects,我有一个带有几个线程循环的程序,您可以将任务发布到其中。其中一个线程循环是UI线程循环。它必须处理窗口消息以及发布的任务,因此我发送WM_用户消息来唤醒调度循环中的线程 问题是有时(特别是当有很多其他窗口消息,如WM_PAINT或WM_RESIZE)我的WM_USER消息不会唤醒线程。似乎PostMessage函数没有从MsgWaitForMultipleObjectsEx调用中唤醒线程,尽管我不知道为什么 这就是它看起来的样子(为了简单起见进行了一些解释): #定义HaveWorkMessag

我有一个带有几个线程循环的程序,您可以将任务发布到其中。其中一个线程循环是UI线程循环。它必须处理窗口消息以及发布的任务,因此我发送WM_用户消息来唤醒调度循环中的线程

问题是有时(特别是当有很多其他窗口消息,如
WM_PAINT
WM_RESIZE
)我的
WM_USER
消息不会唤醒线程。似乎
PostMessage
函数没有从
MsgWaitForMultipleObjectsEx
调用中唤醒线程,尽管我不知道为什么

这就是它看起来的样子(为了简单起见进行了一些解释):

#定义HaveWorkMessage(WM_用户+100)
类ThreadLoopUI{
公众:
ThreadLoopUI()
:myHaveWork(0){}
无效后任务(任务和任务){
{
ScopedLock锁(myMutex);
myTaskQueue.push_-back(aTask);
}
日程安排();
}
无效计划工作(){
if(联锁交换(&myHaveWork,1)){
//无需向消息队列发送垃圾邮件
返回;
}
if(!PostMessage(myHWnd、HaveWorkMessage、reinterpret_cast(this)、0)){

std::cerr不确定它是否是您案例中的罪魁祸首,但是您应该组织代码,以便在目标线程已经有了消息循环之后保证使用
PostMessage()

新线程最初没有任何消息队列,它只是在第一次调用试图从中获取消息后创建的。我不确定
MsgWaitForMultipleObjectsEx()
在这里是否计数,因此我建议在线程开始时调用
peek message()
,以便创建队列


你的应用程序应该保证在
PeekMessage()
返回之前不会向线程发布/发送消息,否则消息可能会丢失。

MsgWaitForMultipleObjects[Ex]
表示它是由于一条或多条消息而返回的,您必须这样做。您的代码只处理一条消息,这意味着第二条消息未被处理。这就是为什么您从未收到您的
WM\U用户
消息:您在有机会看到它之前就放弃了。

我现在已经找到了罪魁祸首,而且在某些情况下,似乎是消息由消息循环之外的窗口从队列中调度(即,它们被自动发送到
WindowProcedure
)。为了解决此问题,我将我的
WindowProcedure
更改为:

LRESULT CALLBACK 
ThreadLoopUI::WindowProcedure( 
    HWND    aWindowHandle, 
    UINT    aMessage, 
    WPARAM  aWParam, 
    LPARAM  aLParam )
{
    switch (aMessage)
    {
    case HaveWorkMessage:
        // This might happen if windows decides to start dispatch messages from our queue
        ThreadLoopUI* threadLoop = reinterpret_cast<ThreadLoopUI*>(aWParam);

        InterlockedExchange(&threadLoop->myHaveWork, 0);

        // Read the next WM_ message from the queue and dispatch it
        threadLoop->PrivProcessNextWindowMessage();

        if (threadLoop->DoWork())
        {
            threadLoop->ScheduleWork();
        }

        break;
    }

    return DefWindowProc(aWindowHandle, aMessage, aWParam, aLParam);
LRESULT回调
ThreadLoopUI::WindowProcedure(
HWND awindowandle,
这是一条消息,
WPARAM aWParam,
LPARAM(阿尔帕兰)
{
开关(A消息)
{
案例信息:
//如果windows决定开始从队列中分派消息,则可能会发生这种情况
ThreadLoopUI*threadLoop=reinterpret_cast(aWParam);
联锁交换(&threadLoop->myHaveWork,0);
//从队列中读取下一条WM_uuu消息并分派它
threadLoop->PrivProcessNextWindowMessage();
如果(threadLoop->DoWork())
{
threadLoop->ScheduleWork();
}
打破
}
返回DefWindowProc(aWindowHandle、aMessage、aWParam、aLParam);

感谢大家的帮助和建议!

什么是“看到了吗?”在标题中???你有没有尝试过
QS_ALLINPUT | QS_ALLPOSTMESSAGE
?没有,但从它看来似乎与
QS_POSTMESSAGE
中包含的
QS_ALLINPUT
相同。我可以尝试一下…编辑:哦,我没有阅读整个页面。似乎它们在清除标志时有所不同。这可能实际上是原因…我会试试看。你说的是真的,但我不认为这是我问题的根源。大多数情况下,此消息传递是有效的,但有时会失败。这与消息是否是第一条消息无关(即在创建队列之前)或者不是。MsgWaitForMultipleObjectsEx变量允许
MWMO\u INPUTAVAILABLE
,这将使它也检查现有的未读输入。如果您发送一条进入模式循环的消息,就会发生这种情况,因为该模式循环不会有您自定义的
HaveWorkMessage
处理程序。是的,我正在发布一个
WM\u EINTERSIZEMOVE
将消息移动到我代码的其他地方,这使窗口进入一个模式循环。