为什么如果我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()
在消息框关闭之前不会执行。但是,计时器会继续运行,并且即使在显示消息框时也会每秒重新绘制一次窗口。因此,虽然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()
,同时仍然允许原始线程在此期间处理其他消息?(那是我没有受过教育的猜测)
提前致谢