【问题标题】:Win32 Application with high CPU usage具有高 CPU 使用率的 Win32 应用程序
【发布时间】:2015-11-27 00:36:36
【问题描述】:

这是我第一次使用 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

【问题讨论】:

  • 使用PeekMessage 不会等待某些东西,因此在循环中这样做将确保CPU一直处于忙碌状态...
  • 您期待什么?您的代码尽可能快地运行。显然,这会烧毁CPU。如果你想让它运行得更慢,那么就这样做。减慢代码的典型解决方案是让它进入睡眠状态。很难理解,为什么您甚至会关心持续呈现内容的应用程序中的 CPU 消耗。
  • 我理解 Mats,但 CPU 使用率是不是有点太高了?如果我检查其他应用程序,例如... VLC,我可以看到它们往往不会出现这种“问题”。
  • 这应该是一个视频播放器,我希望在视频解码开始时开始大处理部分:)

标签: c++ windows winapi visual-c++


【解决方案1】:

标准的 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 上的其他后台应用程序能够运行。

【讨论】:

  • 知道了!我现在将继续不睡觉的代码!谢谢!并感谢其他回答。
  • 我刚刚在问题 cmets 中注意到您这样做是为了渲染视频播放器。如果是这种情况,您可以考虑在单独的线程上进行视频渲染,并直接在您在主线程中创建的 HWND/HDC 的表面上进行绘制。您的主线程使用 GetMessage。您的渲染线程以预期的帧速率解码视频。
  • 这就是我打算做的。另一个快速的问题,Direct3D 是显示解码帧的最佳解决方案吗?我正在尝试重现高达 4K 的视频。
  • 你看过Media Foundation吗?
  • 如果您使用 DirectX,它可以与 vblank 同步,从而以一种时尚的方式为您提供内置睡眠。
【解决方案2】:

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

【讨论】:

  • 显而易见的就不用说了!
  • 为什么不呢?我写一些对我来说显而易见的事情。显然,对您来说,有问题的代码确实实现了持续更新应用程序的标准消息循环,这对您来说并不明显。因此,您的建议没有解决这个问题。下一次,我会在否决您的答案时留下它,而不发表评论。
  • +1。是的,即使在不断更新的应用程序中也是如此。无论如何,这些更新不属于 GUI 线程。为了保持 GUI 响应,GUI 线程应该随时准备好处理消息,而在GetMessage 中被阻止是您实现这一目标的方法。
  • 感谢 MSlaters,这是一个中肯的评论。
  • @MSalters:游戏通常将渲染和消息处理放在同一个线程上。一方面,到达的消息非常少,例如,当如果有调整大小请求,最好在同一个线程上重新创建设备资源。这样你就可以免费获得序列化。如果游戏确实使用键盘输入消息,那么渲染是否发生在同一个线程上都没有关系。如果渲染要减慢输入处理的速度,那么它也太慢而无法及时显示结果。将慢速渲染放在另一个线程上不会给您带来任何好处。
猜你喜欢
  • 2018-10-10
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-08-18
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多