如果MessageBox()/相关是同步的,为什么我的消息循环冻结? [英] If MessageBox()/related are synchronous, why doesn't my message loop freeze?

查看:230
本文介绍了如果MessageBox()/相关是同步的,为什么我的消息循环冻结?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

为什么,如果我调用一个看似同步的Windows函数像 MessageBox()在我的消息循环,循环本身不冻结,如果我调用 Sleep()(或类似的函数)?为了说明我的观点,取以下骨架 WndProc

  = 0; 

LRESULT CALLBACK WndProc(HWND hwnd,UINT msg,WPARAM wParam,LPARAM lParam)
{
switch(msg)
{
case WM_CREATE:
SetTimer(hwnd,1,1000,NULL); //启动1秒定时器
break;
case WM_PAINT:
//绘制/显示计数器变量到窗口
break;
case WM_TIMER://每秒发生
counter ++;
InvalidateRect(hwnd,NULL,TRUE); //强制窗口重绘本身
break;
case WM_LBUTTONDOWN://有人点击窗口
MessageBox(hwnd,,,0);
MessageBeep(MB_OK); //在MessageBox返回后播放声音
break;
//默认....
}
return 0;
}

在上面的例子中,程序的主要功能是运行一个定时器和显示计数器的值每秒。但是,如果用户单击我们的窗口,程序将显示一个消息框,然后在框关闭后发出哔声。



这里是有趣的地方:我们可以告诉 MessageBox()是一个同步函数,因为 MessageBeep()不会执行,直到消息框关闭。但是,计时器仍在运行,即使在显示消息框时,窗口也会每秒刷新一次。因此, MessageBox()显然是一个阻塞函数调用,其他消息( WM_TIMER / WM_PAINT )仍然可以处理。这很好,除非我替换MessageBox另一个阻塞调用像 Sleep()

  case WM_LBUTTONDOWN:
Sleep(10000); //等待10秒
MessageBeep(MB_OK);
break;

这会完全阻止我的应用程序,并且在10秒内不会进行消息处理( WM_TIMER / WM_PAINT 未处理,计数器不更新,程序冻结等)。那么为什么 MessageBox()允许消息处理继续,而 Sleep()不会?鉴于我的应用程序是单线程的, MessageBox()是允许这个功能吗?系统是否复制我的应用程序线程,以这种方式,它可以完成 WM_LBUTTONDOWN 代码一次 MessageBox()完成,同时仍然允许原线程处理其他消息在临时?

解决方案


$ b < MessageBox()和类似的Windows API函数不会阻止执行,就像IO操作或互斥会做的那样。 MessageBox()函数创建一个对话框通常带有一个确定按钮 - 所以你会期望自动处理与消息框相关的Windows消息。这是用自己的消息循环实现的 - 没有创建新的线程,但是你的应用程序仍然响应,因为选择的消息,如Paint,处理函数递归调用您的 WndProc()



Sleep()和其他直接从 WndProc()调用的函数, )处理Windows消息,实际上会阻止单线程消息循环的执行,不会处理其他消息。


Why is it that if I call a seemingly synchronous Windows function like MessageBox() inside of my message loop, the loop itself doesn't freeze as if I called Sleep() (or a similar function) instead? To illustrate my point, take the following skeletal 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;
}

In the above example, the program's main function is to run a timer and display the counter's value every second. However, if the user clicks on our window, the program displays a message box and then beeps after the box is closed.

Here's where it gets interesting: we can tell MessageBox() is a synchronous function because MessageBeep() doesn't execute until the message box is closed. However, the timer keeps running, and the window is repainted every second even while the message box is displayed. So while MessageBox() is apparently a blocking function call, other messages (WM_TIMER/WM_PAINT) can still be processed. That's fine, except if I substitute MessageBox for another blocking call like Sleep()

    case WM_LBUTTONDOWN:
         Sleep(10000); //wait 10 seconds
         MessageBeep(MB_OK);
         break;

This blocks my application entirely, and no message processing occurs for the 10 seconds (WM_TIMER/WM_PAINT aren't processed, the counter doesn't update, program 'freezes', etc). So why is it that MessageBox() allows message processing to continue while Sleep() doesn't? Given that my application is single-threaded, what is it that MessageBox() does to allow this functionality? Does the system 'replicate' my application thread, so that way it can finish the WM_LBUTTONDOWN code once MessageBox() is done, while still allowing the original thread to process other messages in the interim? (that was my uneducated guess)

Thanks in advance

解决方案

The MessageBox() and similar Windows API functions are not blocking the execution, like an IO operation or mutexing would do. The MessageBox() function creates a dialog box usually with an OK button - so you'd expect automatic handling of the Windows messages related to the message box. This is implemented with it's own message loop - no new thread is created, but your application remains responsive, because selected messages like Paint are handled calling recursively your WndProc() function, and some messages are not transmitted to, because of the modal type of the created window.

Sleep() and other functions called directly from your WndProc() handling a Windows message, would actually block the execution of your single threaded Message Loop, no other message would be processed.

这篇关于如果MessageBox()/相关是同步的,为什么我的消息循环冻结?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆