一般在维持消息循环时,都是用while()语句来实现的,下面是我对这两种写法理解,如果错了,请一定指正..//这种写法是当消息队列中有WM_QUIT消息时,循环结束,也就是程序窗口要关闭了,当消息队列中没有消息时,会处于"阻塞"状态,..
//就像是网络编程中的Recv()函数一样,如果没收到信息,则一直处于阻塞.
//我见过大部分书都是这样写的.
while (GetMessage (&msg, NULL, 0, 0))        
{        
    TranslateMessage (&msg) ;        
    DispatchMessage (&msg) ;        
}        
return msg.wParam ;下面是另外一种写法//这种写法是一直无限循环,当消息队列中有消息时,PeekMessage()会立刻返回,不像GetMessage(GetMessage不将控制传回给程
//序,直到从程序的消息队列中取得消息,),所以,可以利用这个特性,在程序空闲时处理一些事情..
while (TRUE)        
{       
    if (PeekMessage (&msg, NULL, 0, 0, PM_REMOVE))        
    {        
            if (msg.message == WM_QUIT)        
                   break ;        
            TranslateMessage (&msg) ;        
            DispatchMessage (&msg) ;        
    }        
    else        
    {        
            // 完成某些工作的其它行程序        
    }        
}        
return msg.wParam ;我现在想问的就是,我读过的关于游戏编程的书中,都用的是第二种方法来维持消息循环,为什么光游戏编程书籍才用这种方法??
而且我觉得第二种方法也不好,它会使CPU的使用率一直保持在90%以上,几乎一直处于100%..

解决方案 »

  1.   

    这个关键是GetMessage和PeekMessage的区别了,其实你是知道这两个的区别的,前者在没有消息时,这个线程被阻塞,也就是不会被分配到时间片,后者当没有消息时,线程还有控制权,它可以被分配到时间片来完成下面的工作,为什么游戏编程用这个,这个和游戏本身有关/
      

  2.   

    我现在想问的就是,我读过的关于游戏编程的书中,都用的是第二种方法来维持消息循环,为什么光游戏编程书籍才用这种方法?? 
    而且我觉得第二种方法也不好,它会使CPU的使用率一直保持在90%以上,几乎一直处于100%..说一点:玩过游戏的都知道 大型游戏中要处理的图形,数据,网络传输等都很多,稍微有点迟钝就会引起整个程序的不流畅,特别是网游用PostMessage则可以将某些优先级较低的处理延迟,从而有更多时间处理UI的互动机制而SendMessage则要求函数返回值,不能区分优先级,整体比较会慢上好多
      

  3.   

    并不是只有游戏编程才用这个啊,其它程序在必要时也会用这个,以前见过一个画随机矩形的程序就是用第二种方法而避免了用定时器,至于游戏用得多也是有原因的,游戏程序在后台要做许多的工作,这个工作放在用户没有操作的空闲时来作是最好的,而这就是第二种方法的优势了,因为第一种方法用户没有操作时,它没有产生消息,这时游戏程序不会被分配时间片。至于占用CPU,这是正常的,你在玩游戏时一般不会做别的事啊
      

  4.   

    while((ret=GetMessage(&msg,MainWnd,0,0))!=0)//接收消息,只有发送的消息为WM_QUIT时,才会返回0
    {

    if(ret==-1)
    {
    return -1;
    }
    else
    {
    TranslateMessage(&msg);//翻译消息
            DispatchMessage(&msg);//消息转发
    }
    }
    return msg.wParam;不然你的机器一直都是100%cpu,即使窗口关闭了,事实上程序还没结束,看任务管理器,可以看到进程依然存在
      

  5.   

    GetMessage在没有消息时会进入等待状态,此时不占用CPU时间。
    PeekMessage无论是否有消息都立即返回,在没有消息的时候可以执行其它代码,在没有事情要处理时应该自己调用Sleep或等待函数(例如WaitMessage),让线程挂起一小段时间。
      

  6.   

    PeekMessage,在处理过程中是线程是一致挂起的,要想休息就用sleep暂停一下
      

  7.   

    GetMessage在没有消息时会进入等待状态,此时不占用CPU时间。 
    PeekMessage无论是否有消息都立即返回,在没有消息的时候可以执行其它代码,在没有事情要处理时应该自己调用Sleep或等待函数(例如WaitMessage),让线程挂起一小段时间。
      

  8.   

    我想第二种循环里面也肯定有释放CPU的地方,不管是阻塞还是主动释放。也见到过有些设备编码时采用用类似的方法,不过总有机制保证不会一致占用CPU。
      

  9.   

    第一个是把所有的消息都交给MFT的默认消息处理过程,第二个是如果有WM_QUIT消息,就先处理WM_QUIT消息,没有就把其它消息交给默认消息处理过程
      

  10.   

    第一种是最简单直接的方法。简单的程序可以这样写。第二种是比较细致点的方法,由于游戏的特殊运行结构(需要不停的刷新屏幕--每秒至少几十次,也就是fps),这种方式比较适用游戏中。但是并不是只有游戏才用第二种方式,很多成熟的APP框架都用这种或者类似这种的方法,包括MFC(CWinApp, CWinThread)。Delphi似乎也提供了OnIdle的事件,因此也多半是这种方式。 因为这种方式提供了检测空闲的方式,至少可以提供一个OnIdle的事件, MFC需要利用空闲执行很多其他的界面刷新操作。
      

  11.   


    你看的是哪的做游戏的书呀.现代的游戏客户端为了更快地得到用户输入等,基本不用系统的消息,用的是directx的方式得到用户输入(键盘或mouse).现在还用系统消息来得到用户输入的游戏估计都是老掉牙的了吧.你第二个例子中如果不加入Sleep()的话,CPU肯定是100%的,随便加个Sleep(1)就不会有这问题的了.
      

  12.   

    第二种方法可以实时的干某些需要实时更新的东西.
    而且一般玩游戏也不需要考虑和其他的应用软件一起运行,当然不用节省cpu空间了............
      

  13.   

    既然需要周期性的更新,为什么不用WM_TIMER呢??
    我知道WM_TIMER存在很多的弊端,一般游戏的帧周期都不会使用WM_TIMER吗???
      

  14.   

    既然需要周期性的更新,为什么不用WM_TIMER呢?? 
    我知道WM_TIMER存在很多的弊端,一般游戏的帧周期都不会使用WM_TIMER吗???
    ===================,
    这个要看具体的程序要求,也不绝对就不用,不过定时器的缺陷比较多。
      

  15.   

    因为WM_TIMER的准确性太差,游戏通常对时间的精确度要求都很高,只有一些简单的情况才会用WM_TIMER。
      

  16.   

    游戏的很多计算可以放在空闲时计算,所以用的是第二种。看看WTL的,也支持OnIdle事件,和你的第二种概念类似。
    int Run()
    {
    BOOL bDoIdle = TRUE;
    int nIdleCount = 0;
    BOOL bRet; for(;;)
    {
    while(bDoIdle && !::PeekMessage(&m_msg, NULL, 0, 0, PM_NOREMOVE))
    {
    if(!OnIdle(nIdleCount++))
    bDoIdle = FALSE;
    } bRet = ::GetMessage(&m_msg, NULL, 0, 0); if(bRet == -1)
    {
    ATLTRACE2(atlTraceUI, 0, _T("::GetMessage returned -1 (error)\n"));
    continue;   // error, don't process
    }
    else if(!bRet)
    {
    ATLTRACE2(atlTraceUI, 0, _T("CMessageLoop::Run - exiting\n"));
    break;   // WM_QUIT, exit message loop
    } if(!PreTranslateMessage(&m_msg))
    {
    ::TranslateMessage(&m_msg);
    ::DispatchMessage(&m_msg);
    } if(IsIdleMessage(&m_msg))
    {
    bDoIdle = TRUE;
    nIdleCount = 0;
    }
    } return (int)m_msg.wParam;
    }
      

  17.   


    我简单提一点:消息循环的存在与否不是以窗口为基础的!一般情况下,你在一个线程中创建了一个窗口,OS 自动为该线程创建一个消息队列,但不只是创建窗口的时候才为线程创建消息队列的,你随便新建一个线程并在其中调用 GetMessage ,OS 就会为它创建消息队列;另外消息循环的退出也不一定与窗口的销毁相对应!我就作过一程序,根本没有窗口,其与其它进程通过线程消息过通讯的!
      

  18.   

    很简单,因为单线程游戏为了实现动画效果,最简单的方式就是不断循环,先进行处理,然后刷新画面,
    即使没有用户输入,也要进行处理,比如一个动作要显示动画,你不按帧不断循环处理,就得用timer,
    问题是timer这个东西不准,而且不能保证一定送达,而且用timer来实现动画,代码的复杂度比 处理、刷新的循环高多了
    当你界面上很多物体都要动画的时候,就要N多timer,代码的逻辑乱的不成样子