2016-01-23 66 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