Вопрос по winapi, windows, c++ – GetMessage с таймаутом

15

Error: User Rate Limit ExceededGetMessage()Error: User Rate Limit ExceededGetMessage()Error: User Rate Limit Exceeded

EDIT:Error: User Rate Limit Exceeded

Error: User Rate Limit Exceeded

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

Error: User Rate Limit Exceededm_quitError: User Rate Limit Exceeded

@rodrigo главным образом потому, что я не разбираюсь в Windows API :), если это рекомендуемый способ, я перейду к этому. qdii
Второй поток запускает & # x2C7; GetMessage & # x2C7; петля. Должен ли я опубликовать код? qdii
Код всегда помогает. Я просто запутался, потому что из-за вашего вопроса кажется, что оба потока заблокированы. Разве вы не можете просто отправить собственное сообщение о том, что "вам нужно закрыть сейчас?" templatetypedef
Вопрос интересный, но я не понимаю, зачем вам это нужно. Как только основной поток готов выйти, он просто должен уведомить весь поток, чтобы закончить (PostQuitMessage Ваш друг здесь), а затем подождите, пока они закончат (WaitForSingleObject, WaitForMultipleObjects) а потом заканчивай сам. rodrigo
Подождите ... какой поток находится в цикле ожиданияGetMessage()? Первый поток, второй поток, или оба? templatetypedef

Ваш Ответ

5   ответов
-1

PeekMessage() вместо. Но я думаю, что это не будет полным решением проблем.

@ Forgoth CallingPeekMessage() было бы отличным решением, если бы я мог соединить его сSleep(1000), но в моем случае второй поток должен быть очень реактивным. +1, потому что решение действительно в других контекстах qdii
4

которую вы всегда можете сделать, это просто отправить заблокированному потоку определенное пользователем сообщение, которое заставит его проснуться, обработать сообщение, а затем вернуться обратно к началу цикла. На самом деле, было бы проще всего полностью удалитьm_quit переменная и вместо этого просто отправить основному потоку сообщение, в котором говорится, что "вам нужно выйти сейчас."

Надеюсь это поможет!

+1, это помогает. Я предпочитаю решение Rodrigo, поскольку оно хранит весь механизм отказа от курения в одном месте. qdii
Это гораздо более чистый метод. Суть потока в том, чтобы получать сообщения, которые говорят ему, что делать. И это не требует, чтобы нить постоянно просыпалась, когда нечего делать.
19

MsgWaitForMultipleObjects без какого-либо объекта.

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

Если, если возвращаетсяWAIT_TIMEOUT это тайм-аут, но если он вернетсяWAIT_OBJECT_0 ты можешь позвонитьGetMessage с гарантией не будет заблокирован.

Но обратите внимание на следующее:

MsgWaitForMultipleObjects does not return if there is unread input of the specified type in the message queue after the thread has called a function to check the queue.

Таким образом, вы должны убедиться, что в последний раз, когда вы вызывали любую из функций сообщений, в очереди не осталось сообщений, иначе у вас будет какое-то состояние гонки.

Вероятно, ваш лучший вариант будет заменитьGetMessage с:

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

Но, как я уже говорил, я не тестировал его, поэтому не уверен, сработает ли он.

Спасибо @ 5andr0 заQS_ALLINPUT было то, что исправило это для меня!
Кроме того, опасность для вас, если вы установите bWaitAll в TRUE, как я обнаружил. Также рассматривается здесь:blogs.msdn.microsoft.com/larryosterman/2004/06/02/…
Я просто зашел в тупик, ожидаяSendMessage MSG с этой рутиной. Вы должны использоватьQS_ALLINPUT вместоQS_ALLEVENTSпотому что это также охватываетQS_SENDMESSAGE, увидетьmsdn для получения дополнительной информации
а это событие лучше qdii
13

UINT_PTR timerId=SetTimer(NULL, NULL, 1000, NULL) перед звонкомGetMessage, Это опубликуетWM_TIMER сообщение в вызывающий поток каждую секунду, поэтомуGetMessage вернется быстро. Затем позвонитеKillTimer(NULL, timerId) отменить это.

UPDATE Образец кода:

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;
}
Довольно странный сторож =)
@qdii - я исправлюсь!
@rodrigo: +1. пока лучшее решение, которое я видел. Я буду ждать, когда появятся другие кандидаты. qdii
@rodrigo следите заmsg это указатель кроме того, указанная структура не имеетuMsg член, это называетсяmessage. qdii
2

сPostThreadMessage.

Например.

PostThreadMessage(threadid, WM_QUIT, 0, 0);

Вам не нужно читатьm_quit переменная во втором потоке, но вы должны проверить на наличие ошибокGetMessage а также возвращаемое значениеFALSE/0 это то, что возвращается, если следующее сообщение является сообщением о выходе.

Похожие вопросы