关于消息循环与Cpu占用率

HengStar 2008-05-22 03:32:36
我的Windows窗口循环封装代码如下

void CGameWindow::MessageLoop( common::FUNCTION_CALL fun_call ) // fun_call是一个函数对象,用来调用渲染函数
{
bool bGotMsg;
MSG msg;
msg.message = WM_NULL;
::ZeroMemory( &msg, sizeof( msg ) );
::PeekMessage( &msg, NULL, 0u, 0u, PM_REMOVE );

while ( WM_QUIT != msg.message )
{
bGotMsg = ( ::PeekMessage( &msg, NULL, 0u, 0u, PM_REMOVE ) != 0 );

if( bGotMsg )
{
if( 0 == TranslateAccelerator( m_hWnd, NULL, &msg ) )
{
::TranslateMessage( &msg );
::DispatchMessage( &msg );
}
}
else
{
//WaitMessage(); // 注意!

fun_call();
}
}
}


以上代码中如果不加WaitMessage()那么该应用程序Cpu占用率始终在50%左右,但是加上以后CPU占用率就只有1%左右了,有人能详细解释一下具体原因吗?加上WaitMessage()会有什么别的隐患吗?还有什么更好的解决方案吗?
...全文
255 15 打赏 收藏 转发到动态 举报
写回复
用AI写文章
15 条回复
切换为时间正序
请发表友善的回复…
发表回复
jameshooo 2008-05-22
  • 打赏
  • 举报
回复
如果只有消息需要处理,用GetMessage;
如果处理消息的同时还想做点别的事,可以使用MsgWaitForMultiObjects
Torch009 2008-05-22
  • 打赏
  • 举报
回复
消息循环里尽量别用sleep
liyinlei 2008-05-22
  • 打赏
  • 举报
回复
可以 PeekMessage 与 GetMessage 搭配使用
HengStar 2008-05-22
  • 打赏
  • 举报
回复
[Quote=引用 11 楼 jameshooo 的回复:]
除非有特定的目的,尽量别用sleep,否则CPU是降了,运行效率也降了
[/Quote]
我想也是啊,感觉用WaitMessage也不好,直接GetMessage似乎问题也不少,我是做游戏,请问高手们还有什么更好的解决方案吗?
jameshooo 2008-05-22
  • 打赏
  • 举报
回复
除非有特定的目的,尽量别用sleep,否则CPU是降了,运行效率也降了
HengStar 2008-05-22
  • 打赏
  • 举报
回复
Sleep(0)似乎没用Sleep(1)可以..
  • 打赏
  • 举报
回复
用sleep(0)代替WaitMessage()也可以降低cpu的使用率
liyinlei 2008-05-22
  • 打赏
  • 举报
回复
// Render a frame during idle time (no messages are waiting)
DXUTRender3DEnvironment();

注释里有解释:处理 idle time, (no messages are waiting 没消息在等待)
jameshooo 2008-05-22
  • 打赏
  • 举报
回复
应该是DXUTRender3DEnvironment中使用了阻塞调用或者消息循环
cnzdgs 2008-05-22
  • 打赏
  • 举报
回复
PeekMessage不等待消息,如果没有执行等待函数就会一直循环执行代码,所以CPU使用率很高。上面的代码应该是在DXUTRender3DEnvironment里面有等待函数吧?
jameshooo 2008-05-22
  • 打赏
  • 举报
回复
线程没有机会被阻塞,所以CPU上去了,GetMessage/WaitFor.../Sleep都能阻塞
HengStar 2008-05-22
  • 打赏
  • 举报
回复

HRESULT DXUTMainLoop( HACCEL hAccel )
{
HRESULT hr;

// Not allowed to call this from inside the device callbacks or reenter
if( GetDXUTState().GetInsideDeviceCallback() || GetDXUTState().GetInsideMainloop() )
{
if( GetDXUTState().GetExitCode() == 0 )
GetDXUTState().SetExitCode(1);
return DXUT_ERR_MSGBOX( "DXUTMainLoop", E_FAIL );
}

GetDXUTState().SetInsideMainloop( true );

// If DXUTCreateDevice*() or DXUTSetDevice() has not already been called,
// then call DXUTCreateDevice() with the default parameters.
if( !GetDXUTState().GetDeviceCreated() )
{
if( GetDXUTState().GetDeviceCreateCalled() )
{
if( GetDXUTState().GetExitCode() == 0 )
GetDXUTState().SetExitCode(1);
return E_FAIL; // DXUTCreateDevice() must first succeed for this function to succeed
}

hr = DXUTCreateDevice();
if( FAILED(hr) )
{
if( GetDXUTState().GetExitCode() == 0 )
GetDXUTState().SetExitCode(1);
return hr;
}
}

HWND hWnd = DXUTGetHWND();

// DXUTInit() must have been called and succeeded for this function to proceed
// DXUTCreateWindow() or DXUTSetWindow() must have been called and succeeded for this function to proceed
// DXUTCreateDevice() or DXUTCreateDeviceFromSettings() or DXUTSetDevice() must have been called and succeeded for this function to proceed
if( !GetDXUTState().GetDXUTInited() || !GetDXUTState().GetWindowCreated() || !GetDXUTState().GetDeviceCreated() )
{
if( GetDXUTState().GetExitCode() == 0 )
GetDXUTState().SetExitCode(1);
return DXUT_ERR_MSGBOX( "DXUTMainLoop", E_FAIL );
}

// Now we're ready to receive and process Windows messages.
bool bGotMsg;
MSG msg;
msg.message = WM_NULL;
PeekMessage( &msg, NULL, 0U, 0U, PM_NOREMOVE );

while( WM_QUIT != msg.message )
{
// Use PeekMessage() so we can use idle time to render the scene.
bGotMsg = ( PeekMessage( &msg, NULL, 0U, 0U, PM_REMOVE ) != 0 );

if( bGotMsg )
{
// Translate and dispatch the message
if( hAccel == NULL || hWnd == NULL ||
0 == TranslateAccelerator( hWnd, hAccel, &msg ) )
{
TranslateMessage( &msg );
DispatchMessage( &msg );
}
}
else
{
// Render a frame during idle time (no messages are waiting)
DXUTRender3DEnvironment();
}
}

// Cleanup the accelerator table
if( hAccel != NULL )
DestroyAcceleratorTable( hAccel );

GetDXUTState().SetInsideMainloop( false );

return S_OK;
}


以上是微软DirectX中的一个Sample中的消息循环函数的源代码,为什么它的运行却耗费CPU很低呢?
liyinlei 2008-05-22
  • 打赏
  • 举报
回复
PeekMessage不管消息队列里有没有消息都会马上返回,有消息返回消息,没消息返回空值,因此占用CPU较高
GetMessage等待到有消息的时候才返回。并且收到WM_QUIT消息是返回0,如此判断可以退出消息循环

要做消息循环的话用GetMessage
七里河蠢才 2008-05-22
  • 打赏
  • 举报
回复
不加的话系统内还有别的线程要用资源,互相争,势必会造成CPU使用上升,而如果用了你说的那个函数,那么系统就卡在这里等着这个函数运行,这个时候系统被挂在了这里,别的也不能动了,所以CPU利用率就没那么高了。
liyinlei 2008-05-22
  • 打赏
  • 举报
回复
PeekMessage 改为GetMessage()
通过性能监控工具nmon的学习,清楚的了解Linux服务器资源CPU、磁盘、内存、网络、进程之间的关联,了解nmon监控结果的字段的含义以及影响,更重要的是通过熟悉监控结果中字段数据的由来,理清性能测试的分析思路,学会性能测试的分析方法。 课程内容:第一章:课程简介课程介绍课程大纲第二章:nmon介绍nmon简介nmon下载nmon安装nmon屏幕统计-交互模式nmon数据统计-数据收集模式nmon进程关闭nmon分析工具nmon数据文件解析第三章:nmon数据分析SYS_SUMM【系统资源汇总】AAA【服务器基本信息】BBBP【Linux执行的命令和结果】CPU_ALL【所有CPU数据的概述】CPU_SUMM【每个CPU的整体用情况】CPU001【CPU001的每个时间点用情况】DISK_SUMM【磁盘的吞吐量和IOPS】DISKBSIZE【磁盘块信息】DISKBUSY【磁盘的繁忙情况】DISKREAD【磁盘的读取操作速率】DISKXFER【磁盘的I/0传输速率】JFSFILE【JFS文件空间使用百分比】MEM【内存】VM【虚拟内存】NET【网络数据传输速率】NETPACKET【网络数据包】PROC【进程】TOP【PID进程相关的CPU/内存等】 课程提供的下载资料:包含通过nmon收集的Linux服务器资源信息ecs-lc_220715_1019.nmon文件,大家在没有Linux服务器的情况下,可以通过对这个文件进行nmon数据解析和数据分析的学习。 

16,472

社区成员

发帖
与我相关
我的任务
社区描述
VC/MFC相关问题讨论
社区管理员
  • 基础类社区
  • Web++
  • encoderlee
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告

        VC/MFC社区版块或许是CSDN最“古老”的版块了,记忆之中,与CSDN的年龄几乎差不多。随着时间的推移,MFC技术渐渐的偏离了开发主流,若干年之后的今天,当我们面对着微软的这个经典之笔,内心充满着敬意,那些曾经的记忆,可以说代表着二十年前曾经的辉煌……
        向经典致敬,或许是老一代程序员内心里面难以释怀的感受。互联网大行其道的今天,我们期待着MFC技术能够恢复其曾经的辉煌,或许这个期待会永远成为一种“梦想”,或许一切皆有可能……
        我们希望这个版块可以很好的适配Web时代,期待更好的互联网技术能够使得MFC技术框架得以重现活力,……

试试用AI创作助手写篇文章吧