17

我有一个应用程序,第二个线程GetMessage()在循环中调用。在某些时候,第一个线程意识到用户想要退出应用程序并通知第二个线程它应该终止。由于第二个线程被卡住GetMessage(),程序永远不会退出。有没有办法等待超时消息?我也对其他想法持开放态度。

编辑:(附加解释)

第二个线程运行该代码片段:

while ( !m_quit && GetMessage( &msg, NULL, 0, 0 ) )
{
    TranslateMessage( &msg );
    DispatchMessage( &msg );
}

第一个线程设置m_quit为 true。

4

5 回答 5

21

未经测试,但您可以在没有任何对象的情况下尝试函数MsgWaitForMultipleObjects 。

MsgWaitForMultipleObjects(0, NULL, FALSE, timeout, QS_ALLINPUT);

如果如果返回WAIT_TIMEOUT它是一个超时,但如果它返回WAIT_OBJECT_0你可以 GetMessage保证不被阻塞调用。

但请注意以下几点:

如果线程调用函数检查队列后消息队列中存在指定类型的未读输入,则 MsgWaitForMultipleObjects 不会返回。

因此,您必须确保上次调用任何消息函数时队列中没有消息,否则您将遇到一种竞争条件。

可能您最好的选择是替换GetMessage为:

if (MsgWaitForMultipleObjects(0, NULL, FALSE, timeout, QS_ALLINPUT) == WAIT_OBJECT_0)
{
    while (PeekMessage(&msg, 0, 0, 0, PM_REMOVE))
    {
        //dispatch the message
    }
}

但正如我之前所说,我没有测试它,所以我不能确定它是否会起作用。

于 2012-06-02T22:37:02.890 回答
19

最简单的方法是在调用UINT_PTR timerId=SetTimer(NULL, NULL, 1000, NULL)之前先调用GetMessage。它会WM_TIMER每秒向调用线程发送一条消息,因此GetMessage会立即返回。然后,打电话KillTimer(NULL, timerId)取消它。

更新示例代码:

BOOL GetMessageWithTimeout(MSG *msg, UINT to)
{
    BOOL res;
    UINT_PTR timerId = SetTimer(NULL, NULL, to, NULL);
    res = GetMessage(msg);
    KillTimer(NULL, timerId);
    if (!res)
        return FALSE;
    if (msg->message == WM_TIMER && msg->hwnd == NULL && msg->wParam == timerId)
        return FALSE; //TIMEOUT! You could call SetLastError() or something...
    return TRUE;
}
于 2012-06-02T22:11:57.240 回答
4

您总是可以做的一件事就是向被阻塞的线程发送一条用户定义的消息,使其唤醒,处理消息,然后返回到循环的顶部。事实上,完全删除m_quit变量可能是最简单的,而是只向主线程发送一条消息,说“你现在需要退出”。

希望这可以帮助!

于 2012-06-02T22:17:29.577 回答
3

您应该能够将退出消息发布到第二个线程PostThreadMessage

例如

PostThreadMessage(threadid, WM_QUIT, 0, 0);

您不需要m_quit在第二个线程中读取变量,但您应该检查错误GetMessage以及返回值,FALSE/0如果下一条消息是退出消息,则返回值。

于 2012-06-02T22:33:52.423 回答
-1

是的。试试PeekMessage()吧。但我认为这不会完全解决问题。

于 2012-06-02T22:10:38.113 回答