Почему это так, что если я вызову, по-видимому, синхронную функцию Windows, такую как MessageBox()
внутри моего цикла сообщений, сам цикл не замерзает, как если бы я называл Sleep()
(или подобную функцию) вместо этого? Чтобы проиллюстрировать мою мысль, сделайте следующий скелет WndProc
:
int counter = 0;
LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
switch (msg)
{
case WM_CREATE:
SetTimer(hwnd, 1, 1000, NULL); //start a 1 second timer
break;
case WM_PAINT:
// paint/display counter variable onto window
break;
case WM_TIMER: //occurs every second
counter++;
InvalidateRect(hwnd, NULL, TRUE); //force window to repaint itself
break;
case WM_LBUTTONDOWN: //someone clicks the window
MessageBox(hwnd, "", "", 0);
MessageBeep(MB_OK); //play a sound after MessageBox returns
break;
//default ....
}
return 0;
}
В приведенном выше примере основной функцией программы является запуск таймера и отображение значения счетчика каждую секунду. Однако, если пользователь нажимает на наше окно, программа отображает окно сообщения и затем выдает звуковой сигнал после закрытия окна.
Здесь, где это становится интересным: мы можем сказать, что MessageBox()
является синхронной функцией, потому что MessageBeep()
не выполняется, пока окно сообщения не будет закрыто. Тем не менее, таймер продолжает работать, и окно перекрашивается каждую секунду, даже когда отображается окно сообщения. Таким образом, хотя MessageBox()
, по-видимому, является вызовом функции блокировки, другие сообщения (WM_TIMER
/WM_PAINT
) могут обрабатываться. Это прекрасно, если я не заменю MessageBox на другой блокирующий вызов, например Sleep()
case WM_LBUTTONDOWN:
Sleep(10000); //wait 10 seconds
MessageBeep(MB_OK);
break;
Это полностью блокирует мое приложение, и обработка сообщений не выполняется в течение 10 секунд (WM_TIMER
/WM_PAINT
не обрабатывается, счетчик не обновляется, программа "зависает" и т.д.). Так почему же MessageBox()
позволяет обрабатывать сообщения, пока Sleep()
нет? Учитывая, что мое приложение однопоточно, что делает MessageBox()
, чтобы разрешить эту функцию? Система "реплицирует" мою прикладную нить, так что она может закончить код WM_LBUTTONDOWN
один раз MessageBox()
, но при этом разрешая исходному потоку обрабатывать другие сообщения в промежуточный период? (это была моя необразованная догадка)
Заранее спасибо