題 Windows如何知道程序是否沒有響應?


Windows如何知道程序是否沒有響應?它是否會不斷輪詢所有正在運行的應用程序?


171
2017-08-24 07:33


起源


hurryupandwait.io/blog/detecting-a-hung-windows-process - magicandre1981
@ magicandre1981該頁面提出了一種方法來檢查程序是否正在積極地做某事,但這不是Windows實際使用的方式。 - Kevin Panko
查看Windows消息隊列,候選者是PeekMessage()函數 - Luciano


答案:


應用程序從Windows提供的隊列中獲取事件。

如果應用程序不會輪詢事件隊列一段時間(5秒),例如在進行長時間計算時,則Windows會假定應用程序已掛起並向用戶發出警報。

為避免應用程序將昂貴的計算推送到工作線程或拆分處理,並確保定期輪詢隊列。


149
2017-08-24 10:09



↑這個。與接受的答案中建議的時間安排無關,只與您是否經常打電話有關 GetMessage (或類似的)和 DispatchMessage。 - Damon
接受的答案,在提到 IsHungAppWindow 正確地指出啟動階段的程序不必調用 GetMessage。 - MSalters
@MSalters將啟動定義為第一個之前的時間 GetMessage?該功能允許簡單的命令行應用程序工作而不被視為掛起,因為它們不需要輪詢隊列。 - ratchet freak
@ratchetfreak:大概是在第一次CreateWindow調用之前。命令行應用程序是完全不同的野獸;它們在ConHost.EXE中運行,並且它與Windows GUI系統交互。 - MSalters
此外,在我看來,在Windows 7(可能更早)中,如果您嘗試以某種方式操作窗口,Windows將會更快地註意到這一點。就像一個程序不處理最大化或移動消息一樣,Windows 7將在大約1或2秒後跳轉到沒有響應。 - Dave Cousineau


Windows如何知道程序是否沒有響應?

如果沒有Windows的源代碼,我們無法確定它在內部的作用。

有一個SDK Windows功能 IsHungAppWindow 可以使用。

如果應用程序沒有等待輸入,不在啟動處理中,並且沒有調用,則認為應用程序沒有響應 的PeekMessage 在5秒的內部超時時間內。

資源 IsHungAppWindow功能

如果頂級窗口停止響應消息超過幾秒鐘,系統會認為該窗口沒有響應。在這種情況下,系統會隱藏窗口並將其替換為具有相同Z順序,位置,大小和可視屬性的重影窗口。這允許用戶移動它,調整它,甚至關閉應用程序。但是,這些是唯一可用的操作,因為應用程序實際上沒有響應。

資源 關於消息和消息隊列


它是否會不斷輪詢所有正在運行的應用程序?

不會。應用程序不會被輪詢,但給定處理器時間。

Windows有一個調度系統,可以為應用程序線程提供處理器時間。

調度算法很複雜,並在其中進行了詳細描述 Windows Internals,第1部分(第6版)(開發人員參考)


78
2017-08-24 08:48



掛起狀態不基於CPU。大多數程序在99.999%的時間內都是“懸掛”的,並且什麼都不做。 - usr
@usr我在哪裡說“掛”取決於CPU? - DavidPostill♦
@usr答案的前半部分是回答“它是否一直在輪詢所有正在運行的應用程序?”。下半部分回答“Windows如何知道程序是否沒有響應?”OP在一個問題中提出兩個問題;) - DavidPostill♦
但這不是真正的民意調查,是嗎?我假設內部更像是窗口上的等待句柄,當你打電話時發出信號 PeekMessage。因此,當Windows向應用程序發送消息,並且在五秒鐘內未收到消息時,它會將應用程序標記為無響應。事實上,在最近的Windows上,如果窗口無法響應,則窗口僅標記為“無響應” 用戶 及時輸入 - 直到我嘗試單擊或按某個鍵或某個鍵,應用程序可以輕鬆地“掛起”幾分鐘而不會“顯示”無響應。 - Luaan
您可以刪除“關於消息和消息隊列”上面的所有內容,因為它無法解決問題。 Windows知道應用程序已停止響應,因為它停止傳送消息。該應用程序可能正在運行,因為它做了一些密集而不是抽取消息(但這是一個設計糟糕的程序)。 - Andy


實際上,Windows並不總是知道應用程序沒有響應。應用程序必須是帶窗口的交互式應用程序,窗口必須接收應用程序無法處理的消息,然後Windows才會斷定應用程序沒有響應。

例如,Windows無法知道沒有從命令行運行的用戶界面的數字運算應用程序是在做它的事情,還是可能陷入無限循環。

Windows中的交互式圖形應用程序通過連續輪詢消息隊列來接收事件。 Windows使用鍵盤,鼠標,計時器等事件填充此消息隊列。如果應用程序無法輪詢消息隊列一段時間(5秒是IsHungAppWindow()函數文檔中提到的超時),Windows會認為應用程序“掛起”,它可能通過更改窗口標題指示(添加文本“ (無響應)“或本地化版本中的等效文本”,如果用戶嘗試與窗口交互,則灰顯窗口內容。

應用程序可能會以Windows無法識別的方式掛起。例如,應用程序可以繼續輪詢其消息隊列中的消息而不對它們進行適當的操作,因此對於所有實際意圖和目的,如果沒有Windows識別它是無響應的,它將顯示為“掛起”。


32
2017-08-24 11:12



根據定義,沒有響應意味著不處理窗口消息,因此它不適用於服務或控制台應用程序,所以我會說Windows總是知道應用程序是否沒有響應。你混淆了死鎖而沒有回應。 - Andy
當然,它可以知道程序是否沒有響應。 “沒有回應”與“陷入無限循環”不同 - BlueRaja - Danny Pflughoeft
實際上,應用程序可以通過GetMessage()檢索消息並且無法處理它們,並且它不會被Windows識別為“沒有響應”,儘管事實上它肯定對用戶沒有響應。術語“不響應”也經常用於描述網絡,服務,交互式命令行等應用程序; AFAIK沒有正式定義將短語限制為窗口化應用程序。死鎖或無限循環(或任何其他編程錯誤)都可能導致應用程序無響應,但不,我沒有混淆因果關係。 - Viktor Toth


Windows是一個操作系統,它監督所有正在運行的程序。

Windows使用事件與基於窗口的應用程序通信。每個程序都有一個不斷監聽傳入事件並處理它們的線程。例如,當您單擊按鈕或通知區域圖標時,Windows會生成一個事件並將其提供給適當的進程。然後,該過程可以決定如何處理它。

所有與程序的交互都是基於事件的,因此當程序不處理傳入事件的時間過長時,就意味著它沒有響應。正如@DavidPostill發現並註意到的那樣 他的回答,超時是5秒。 PeekMessage 是從事件隊列中獲取事件的函數。


10
2017-08-24 09:00





你的問題的答案是肯定/否定。

雖然Windows操作系統可以並且確實使用Windows Messaging Queue中的事件輪詢應用程序,但程序完全沒有義務鏈接到WinAPI或處理/應答Windows隊列。即使回答隊列中的消息也不會告訴Windows該程序是否已“鎖定”。這是一個指標,但就是這樣。真正的答案要復雜得多。

真正的答案

人們正在圍繞這裡的實際答案進行對沖。確定程序是否“沒有響應”是“停止問題“,這在計算機科學中是正式不可判定的。簡短的解釋是,處理器不能作為第三方觀察自己來確定一個子程序是否卡在一個無限循環中,沒有做任何事情來增加一個終止於某個固定的計數器,正常的數字。這兩個都可以被認為是緊閉的循環。一個停止,另一個永遠不會終止。即使你作為一個人,也不知道一個程序是否真的響應,特別是如果它在一個緊閉的循環 - 你只知道是否 認為應該 (響應)。

從Windows的角度來看,這兩個循環都是 “沒有回應”。這就是為什麼Windows讓你可以選擇等待或終止,因為它無法分辨。

所以推論是“為什麼Windows知道這個過程  響應?“答案相當聰明。當一個進程在多線程和多進程操作系統中編譯時,有時甚至在緊密閉合的循環中,編譯器可能會添加一個 讓() 命令,它向處理器提供方便的通知,它可以切換到其他正在運行的進程。它“放棄”處理器和“上下文切換”(因為它被稱為)發生,允許操作系統(包括Windows)回答堆棧中的其他事件,其中一些包括跟踪該過程 具有 回應。

**這並不意味著響應過程會 終止。 ** 無限循環內的進程可以產生處理器,允許Windows處理其他事件。

在某些Windows程序中,程序將處理Windows操作系統信號,這可以告訴操作系統它“正在響應”,但沒有任何程序有義務這樣做。您可以編寫非常簡單的CPU佔用,非終止程序,甚至在Windows上的更高級語言,如perl,php,python和Windows可能無法檢測到它沒有終止並且沒有響應。此時,Windows依賴於啟發式算法 - CPU負載,內存,當程序運行“猜測”時處理器處理的中斷數。同樣,在那時,Windows必須要求你終止,因為它真的不知道它是否應該。

另見Viktor(正確)答案。忽略關於“無響應”是否與無限循環不同的評論。在沒有通知Windows消息隊列的情況下,應用程序可能會或可能不會處理各種消息,中斷和循環。處理消息隊列只是操作系統保持計數器嘗試的多種事件之一 猜測 流程是否掛起。


0
2018-03-14 02:57