Почему это так, что если я вызову, по-видимому, синхронную функцию 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(), но при этом разрешая исходному потоку обрабатывать другие сообщения в промежуточный период? (это была моя необразованная догадка)
Заранее спасибо