高CPU使用率的Win32应用程序

6
这是我第一次与Windows应用程序打交道,有点沮丧。我只有一个简单的代码,创建了一个Win32(Visual C++)GUI应用程序,但一旦我启动可执行文件,我的CPU占用率就会上升到30%(超过应用程序),在寻找解决方法时,我发现有人说在消息循环(GetMessage或PeekMessage)中休眠10毫秒可以解决这个问题,而事实证明确实如此。但由于这是一个事件处理程序循环,我不想突然间让我的代码休眠,希望能够得到一些解决方案的解释。
下面是“问题区域”的概述。
while (TRUE) {
    if (PeekMessage(&g_Msg, NULL, 0, 0, PM_REMOVE)) {
        TranslateMessage(&g_Msg); // translate keystroke messages into the right format
        DispatchMessage(&g_Msg); //Send the message to the WindowProc function
        if (g_Msg.message == WM_QUIT)
            break;
    } else {
        // Run d3d code here
    }
    // Sleep(1); REDUCES CPU!
}

感谢您提前的帮助。
Caio Guedes

2
使用 PeekMessage 不会等待任何东西,因此在循环中这样做将确保 CPU 一直处于繁忙状态... - Mats Petersson
你期望什么?你的代码已经以最快的速度运行了。显然,这会消耗 CPU 资源。如果你想让它运行得更慢,那就这么做吧。减缓代码的通用解决方案是将其置于睡眠状态。很难理解为什么你在一个不断渲染内容的应用程序中会关心 CPU 的消耗。 - IInspectable
我理解你的意思,Mats,但是CPU使用率是否有点太高了?如果我检查其他应用程序,比如……VLC,我可以看到它们不会出现这种“问题”。 - caiomcg
2
这应该是一个视频播放器,我希望在视频解码开始时启动大的处理部分 :) - caiomcg
2个回答

4

一个标准的Windows应用程序循环使用GetMessage。GetMessage会阻塞,直到有输入或者应用程序中需要运行的东西。

MSG msg;
while (GetMessage(&msg, NULL, 0, 0))
{
    TranslateMessage(&msg);
    DispatchMessage(&msg);
}

你编写的代码适用于一个游戏,符合标准——当你需要DirectX尽可能快地渲染帧时,同时还要为其他进程中的窗口和Win32 API传递消息。你编写的方式基本上使用了整个CPU核心。如果你有四核CPU,那么你至少使用了25%,所以30%的测量结果似乎是准确的。
定期使用 Sleep(0)Sleep(1) 语句可以让主线程让出时间片给其他线程和进程。虽然会牺牲一些帧率,但如果游戏需要进行网络和声音等其他线程操作,则有时这是必要的。但由于你拥有多核CPU,因此你可能不需要这样做,因为其他核心可以为这些线程提供服务。
在超线程和多核出现之前,使用 Sleep 语句是不占用太多资源的正常方式。它允许Windows上的其他后台应用程序能够运行。

这就是我想要做的。另一个快速问题,Direct3D是显示解码帧的最佳解决方案吗?我正在尝试重现高达4K的视频。 - caiomcg
你看过媒体基础架构(Media Foundation)了吗? - selbie
在跨线程渲染到设备上下文时,请记住DC具有一定程度的线程亲和性。您将需要手动协调访问。请参阅用户界面对象的线程亲和性第2部分:设备上下文 - IInspectable
1
如果您正在使用DirectX,它可以与vblank同步,从而以某种方式为您提供内置的Sleep。 - Jonathan Potter
@selbie,你所说的“旧日”,是指Win16协作调度。而单处理器的Win32则采用了抢占式调度。 - David Heffernan
显示剩余7条评论

-1
你应该使用GetMessage()函数,它是一个阻塞函数。它会一直阻塞直到有东西需要处理。

不必言明! - Gilles Richer
为什么不呢?我写的是对我来说显而易见的事情。显然,你没有意识到问题中的代码确实实现了一个持续更新应用程序的标准消息循环。因此,你的建议并没有解决问题。下次,我会直接将你的答案点踩,而不留言。 - IInspectable
+1。即使在一个持续更新的应用程序中也是如此。这些更新本来就不属于GUI线程。为了保持GUI的响应性,GUI线程应该随时准备处理消息,并且在GetMessage中被阻塞就是实现这一点的方法。 - MSalters
谢谢MSlaters,这是一个相关的评论。 - Gilles Richer
@MSalters:游戏通常将渲染和消息处理放在同一个线程上。首先,到达的消息非常少,当例如调整大小请求进来时,最好在同一个线程上重新创建设备资源。这样你就可以免费获得序列化。如果游戏确实使用键盘输入消息,那么无论渲染是否发生在同一个线程上都没有关系。如果渲染速度变慢会影响输入处理,那么它也太慢了,无法及时显示结果。将缓慢的渲染放在另一个线程上对你毫无帮助。 - IInspectable

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接