MessageBox()
メッセージ ループ内のように一見同期の Windows 関数を呼び出すと、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()
ただし、タイマーは実行され続け、メッセージ ボックスが表示されている間でもウィンドウは 1 秒ごとに再描画されます。そのため、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()
ようにしながら、その間に元のスレッドが他のメッセージを処理できるようにしますか? (それは私の根拠のない推測でした)
前もって感謝します