2016-01-23 65 views
1

我正在使用DirectX和WINAPI处理家庭项目。我刚刚发现了一个有趣的行为。了解Windows API中消息处理的不同策略

在下面的代码,如果我用我的wndd->h_(类型:HWND),究竟是什么的CreateWindowEx()结果,在PeekMessage()作为第二个参数,然后在主循环开始在单个核心的工作更重的负载,而将第二个参数保留为0,然后计算扩展良好。

void WinLoop() { 
    while (!wndd->exit_) { 
     //if (PeekMessage(&(wndd->msg_), 0, 0, 0, PM_REMOVE)) {  //NOTE : Frequently changing what core is loaded 
     if (PeekMessage(&(wndd->msg_), wndd->h_, 0, 0, PM_REMOVE)) { //NOTE : Heavy load on one core 
      TranslateMessage(&(wndd->msg_)); 
      DispatchMessage(&(wndd->msg_)); 
     } 

     //TODO : update 
     //TODO : draw 
     //TODO : calculate statistic 
    } 
} 

一切似乎工作得很好,但我无法找到任何有关此信息。引擎盖下是什么?

回答

1

根据the documentation对于PeekMessage函数,第二个参数是…

的hWnd [在,可选]

类型:HWND

句柄其消息是要检索的窗口。该窗口必须属于当前线程。

如果的hWndNULLPeekMessage对于属于当前线程的任何窗口,并且对当前线程的消息队列,其HWND值为NULL任何消息(见MSG结构)中检索消息。因此,如果hWnd是NULL,则会处理窗口消息和线程消息。

如果hWnd为-1,PeekMessage检索对当前线程的消息队列,其HWND值NULL作为张贴由PostMessage(当hWnd参数是NULL)或仅消息,也就是线程消息PostThreadMessage

同样重要的是要注意什么PeekMessage功能。简而言之,它将检索队列中存在的第一条消息(匹配指定的条件,如果适用)。因为你已经指定了PM_REMOVE标志,所以它也从中删除了该消息来自队列。

更有趣的是如果队列中没有消息给你,会发生什么情况。在这种情况下,PeekMessage立即返回false。

您现在有足够的信息来了解两个函数调用之间的行为差​​异。在第一种情况下,您传递NULL作为第二个参数,因此PeekMessage函数正在检索属于当前线程的任何窗口的消息以及线程消息。在第二种情况下,您将作为第二个参数传递给特定窗口的句柄,因此PeekMessage函数正在为该窗口检索消息。因为与所有窗口和线程相比,要为这一个窗口检索的消息要少很多,所以PeekMessage函数大多只是返回false。处理消息花费的时间很少。一旦它返回false,你的while循环开始,循环回到开始并再次调用PeekMessage函数。

基本上,你已经创建了一个紧密的循环,只是坐在和烧伤的CPU时间,轮询PeekMessage功能持续不什么,它与操作系统的执行调度干扰。当然,应用程序仍然可以被预先占用,但是您可以保证使用您分配的时间片的100%。

这种行为有一个目的,就像编写游戏时一样。在进行冗长的后台处理但希望继续抽取消息以保持UI响应的应用程序中,通常还会使用循环。但是没有理由在正常应用程序的消息循环中使用PeekMessage,因为您不需要实时处理。相反,你需要GetMessage函数,实际上等待,直到它在返回之前收到一条消息。这在CPU时间方面效率更高,因为它不会持续轮询。你得到你需要的时间,但没有更多。 It is also much more battery-friendly

我认为,如果你与DirectX玩,你可能正在试图写一个游戏或屏幕保护程序或其他一些准实时的东西,这就是为什么你正在使用中的PeekMessage功能第一名。但是您可能想要将NULL作为函数的第二个参数,因为您要处理所有窗口和线索消息,而不仅仅是主窗口的消息。

+0

非常感谢!我只是在一秒钟内测量这样的CPU中可以烧掉多少次迭代。有趣的是PeekMessage()条件,所有的窗口消息都旋转得更快o.O我在这里错过了什么? – NMD

+1

我不明白,这个答案如何解决这个问题。在典型的DirectX应用程序中,通常只有一个窗口,唯一的公共线程消息是“WM_QUIT”。在这些前提下,过滤这个单独窗口的消息不会占用*“少得多的消息”*。即使是这样,它也没有解释为什么不过滤消息会在所有内核之间传播CPU负载。 – IInspectable

+0

我想如果你设置PeekMessage到一个特定的窗口,它可以在“一个”线程中完成。我是这里的小伙子,我只是猜测......如果你有很多窗口,那么低级别的东西会尝试用多个线程来管理它。但是......问题是:当PeekMessage必须处理“更少”的消息时,为什么地狱循环会变慢o.O – NMD