C ++ Функция не работает в то время как (GetMessage (...)) {...} - PullRequest
0 голосов
/ 26 июня 2018

Я был действительно смешным. Пока я занимался программированием на C ++, нужно было долго ждать. Поэтому я решил использовать while(){...}.

Режим 1: Если я использую while (1) {...},
процессор будет находиться под наибольшей нагрузкой. (Требуется максимальная нагрузка на один процессор.)

Режим 2:

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

Уменьшит нагрузку на процессор.
Однако существует большая разница в выполнении операторов между while(1){...} и while(GetMessage(&msg, NULL, 0, 0)){...}.

Например,

Режим 1

dwEndTime = time(NULL) + 120;
while(1)
{
    if(IsOutOfTime())
        break;
}

И

Режим 2

dwEndTime = time(NULL) + 120;
while(GetMessage(&msg, NULL, 0, 0)
{
    if(IsOutOfTime())
        break;

    TranslateMessage(&msg);
    DispatchMessage(&msg);
}

Реализация IsOutOfTime():

BOOL IsOutOfTime()
{
    if(time(NULL) >= dwEndTime)
        return TRUE;

    return FALSE;
}

Результаты в разных результатах выполнения. break не работает в режиме 2 .

Кто-то, пожалуйста, помогите мне решить эту проблему.

Если я даю Sleep(...) в while (1) {...}, я могу уменьшить нагрузку на процессор, но я ненавижу такой стиль кодирования.

1. Какая внутренняя разница между Режимом 1 и Режимом 2 .
2. Я неправильно использовал Режим 2 ?
3. Как уменьшить нагрузку на процессор, не используя sleep.

Ответы [ 5 ]

0 голосов
/ 27 июня 2018

ОК, поскольку вы, похоже, боретесь с SetTimer() (что выглядит здесь как лучшее решение), я выложу полный исходный код для вас. Это действительно очень просто, пожалуйста, перестаньте возиться с занятыми циклами.

Примечание: этот код не нуждается в окне, но ему нужен цикл обработки событий (но вы, кажется, с этим согласны).

Установка:

VOID CALLBACK MyTimerProc (HWND hwnd, UINT uMsg, UINT_PTR idEvent, DWORD dwTime);
DWORD dwTimerID = SetTimer (NULL, 0, 120 * 1000, MyTimerProc);  // 2 minute timeout

Цикл сообщений (НЕ проверяйте время ожидания здесь):

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

Таймер срабатывания:

VOID CALLBACK MyTimerProc (HWND hwnd, UINT uMsg, UINT_PTR idEvent, DWORD dwTime)
{
    KillTimer (NULL, dwTimerID);
    // Do whatever it is you wanted to do when your timeout elapsed
}
0 голосов
/ 26 июня 2018

Самый простой способ заставить поток ждать в течение определенного периода времени - это использовать Sleep():

Sleep(1000 * 120);

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

В этом случае вы можете использовать SetTimer(), и ваш цикл обработки сообщений GUI обрабатывает WM_TIMER сообщений по мере необходимости.

Другой вариант - вместо этого использовать Таймер ожидания , например:

HANDLE hTimer = CreateWaitableTimer(NULL, TRUE, NULL);

LARGE_INTEGER liDueTime;
liDueTime.QuadPart = -10000000 * 120;
SetWaitableTimer(hTimer, &liDueTime, 0, NULL, NULL, FALSE);

// wait for hTimer to be signaled...

CloseHandle(hTimer);

В потоке графического интерфейса вы можете использовать MsgWaitForMultipleObjects(), чтобы дождаться сигнала таймера, продолжая обслуживать сообщения графического интерфейса, например:

HANDLE hTimer = CreateWaitableTimer(NULL, TRUE, NULL);

LARGE_INTEGER liDueTime;
liDueTime.QuadPart = -10000000 * 120;
SetWaitableTimer(hTimer, &liDueTime, 0, NULL, NULL, FALSE);

bool keepLooping = true;
do
{
    DWORD ret = MsgWaitForMultipleObjects(1, &hTimer, FALSE, INFINITE, QS_ALLINPUT);
    if (ret == WAIT_OBJECT_0)
    {
        // timer elapsed ...
        break;
    }

    if (ret == (WAIT_OBJECT_0 + 1))
    {
        MSG msg;
        while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
        {
            if (msg.message == WM_QUIT)
            {
                PostQuitMessage(msg.wParam);
                keepLooping = false;
                break;
            }

            TranslateMessage(&msg);
            DispatchMessage(&msg);
        }
    }
}
while (keepLooping);

CloseHandle(hTimer);

Если вам не нужно обрабатывать сообщения GUI во время ожидания по таймеру, тогда вы можете использовать WaitForSingleObject() или WaitForMultipleObjects() (в зависимости от того, ожидаете ли вы только на таймере или ожидании на других объектах):

HANDLE hTimer = CreateWaitableTimer(NULL, TRUE, NULL);

LARGE_INTEGER liDueTime;
liDueTime.QuadPart = -10000000 * 120;
SetWaitableTimer(hTimer, &liDueTime, 0, NULL, NULL, FALSE);

WaitForSingleObject(hTimer, INFINITE);

CloseHandle(hTimer);
0 голосов
/ 26 июня 2018

WinAPI содержит некоторые функции, которые позволяют ожидать события, функции WaitForSingleObject, WaitForMultipleObject (и их расширение ...Ex. Такое ожидание не нагружает процессор, поскольку процесс находится в состоянии ожидания.

Если у вас есть программа с графическим интерфейсом и вы хотите, чтобы она реагировала, вы должны использовать в цикле функцию * 1006. * Если вам нужно подождать один объект, она выдаст:

DWORD cr
while ((cr = MsgWaitForMultipleObjects(1, &handle, FALSE, milli_sec_timeout, QS_ALLINPUT)) {
    if (cr == WAIT_OBJECT_0) {
        // event has been signaled process it
        break;
    }
    else if (cr == WAIT_OBJECT_0 + 1) {
        // something has arrived in the thread event loop: process the message
        GetMessage(&msg, NULL, 0, 0);
        TranslateMessage(&msg);
        DispatchMessage(&msg);
    }
    else if (cr == WAIT_TIMEOUT) {
        // timeout has elapsed
        ...
    }
    else { // abnormal condition, see doc for more
        ...
    }
}
0 голосов
/ 26 июня 2018

Я решил свою проблему. while(GetMessage(..)){..} is BLOCKED .
Я использовал GetMessage() в while(...) плохо.
Потому что, если нет сообщения для перевода и отправки, GetMessage будет block до тех пор, пока не произойдет какое-либо сообщение.
Итак, я реализовал свой код следующим образом.

#define MESSAGE_NOT_OUT_OF_TIME WM_USER+1
#define MESSAGE_OUT_OF_TIME WM_USER+2

PostMessage(NULL, MESSAGE_NOT_OUT_OF_TIME, 0, 0);

while(GetMessage(&msg, NULL, 0, 0)
{
    if (MESSAGE_NOT_OUT_OF_TIME == msg.message)
        IsOutofTime();

    if (MESSAGE_OUT_OF_TIME == msg.message)
        break;

    TranslateMessage(&msg);
    DispatchMessage(&msg);
}

Реализация IsOutofTime()

VOID IsOutofTime()
{
    if(dwEndTime <= time(NULL))
        PostMessage(NULL, MESSAGE_OUT_OF_TIME, 0, 0);
    else
        PostMessage(NULL, MESSAGE_NOT_OUT_OF_TIME, 0, 0);
}

Хотя загрузка CPU составляет около 70 ~ 80%, я нашел причину и решил проблему.

0 голосов
/ 26 июня 2018

Оба режима 1 и 2 следует избегать, если это возможно, потому что оба опроса опрашивают, чтобы проверить, не вышло ли у вас время.

Режим 1 занимает 100% ЦП и не будет обрабатывать сообщения Windows.
Режим 2 проверяет только время ожидания при получении сообщения, поэтому он может пропустить время ожидания.

Вместо этого вы должны использовать таймер , который сработает, когда у вас закончится время.GetMessage вернет сообщение WM_TIMER по истечении таймера.(Я предполагаю, что IsOutOfTime просто проверяет, что прошло некоторое время).

...