2015-10-29 172 views
2

我有一個System.Diagnostics.Process的實例,它是通過Process.GetProcessesByName創建的。Process.HasExited競爭條件

我成功打開該進程後,執行各種操作,例如讀取其內存和窗口標題。

這個操作是基於一個定時器不斷執行的,我的意思是Timer.Elapsed事件處理程序是過程操作的來源。

現在,我注意到,我有一個競爭條件,我一直無法使用我知道的任何東西來解決。這是怎麼回事了:

timerElapsedEvent(...) { 

    if (!process.HasExited) { 

     process.Refresh(); // Update title. 
     var title = process.MainWindowTitle; 
    } 

} 

如果該進程正在運行,我的代碼進入if塊,有一個小的機會在執行process.MainWindowTitle調用之前的過程可能會退出,這將導致異常。

我需要的是一個辦法以某種方式捕捉過程的退出事件,並保持它活着,直到可以安全地關閉它沒有崩潰我的應用程序,它正在監視它,從而確保它會等待process.MainWindowTitle關閉之前(或任何其他可以解決此問題的解決方案)。

此外,與此同時,另一種方法可能會運行ReadProcessMemory,這也會崩潰。

我該如何解決這個問題?

PS:Process.Exit事件處理程序不起作用,因爲它不會在process.MainWindowTitle之前被觸發,它只會在當前指令完成後觸發。 我敢肯定,以某種方式控制退出事件是解決此問題的唯一方法,因爲HasExit可能會隨時更改,而不會在實際調用過程中的方法之前進行多少次檢查。

PS2:我剛剛意識到這是一個TOCTTOU情況,除非我可以控制我打開的過程,否則它是無法解決的,所以我只是爲了看看有沒有人知道這種方法。

+0

簡單地捕獲'InvalidOperationException'並將其視爲已退出的進程有什麼問題?在處理外部過程時,存在各種各樣的基本上難以解決的競爭條件;你的代碼只需要準備好處理可能發生的錯誤。 –

+0

嘿,彼得!捕捉異常沒什麼問題,我只是想確保沒有辦法同步這些線程或其他東西,這是沒有解決方案的。 – victor

+0

無論你做什麼(在理由之內......如果你準備rootkit系統並接管Windows內核,我想你可以做任何你想要的東西:)),這個過程可能會被殺死,沒有任何可能與它同步。就像人們必須始終準備好趕上'FileNotFoundException'一樣,即使剛剛看到過'File.Exists()'返回'true',你自己的代碼也需要始終爲進程準備好退出,即使Process.HasExited '財產剛剛返回'true'。 –

回答

2

短版:你不行。

這裏有一個基本的「檢查到使用時間」的問題,你沒有足夠的控制來解決。在您檢查HasExited屬性和檢查MainWindowTitle屬性之間,操作系統始終能夠終止您正在處理的流程(任意或由於流程中出現故障)。

Process類對於強制執行異常沒有太大的作用,但它的確做到了。特別是,調用Refresh()會強制課程「忘記」任何有關該過程的知識,以便在您再次請求時重新獲取信息。這包括該過程的主窗口句柄。

Process類使用本機窗口枚舉函數來搜索已知進程ID的窗口句柄。由於該進程已退出,因此無法找到該句柄,並返回一個NULL值(受管理術語爲IntPtr.Zero)。在看到空返回值時,類Process強制調用InvalidOperationException


唯一可靠的解決方案是始終準備好迎接異常。在檢查國家和試圖做一些依賴它的事情之間總會有一個機會,那個國家可能會改變。


雖然學業,我覺得很有趣的是,如果你設置了EnableRaisingEvents屬性,則Process類可以(而且通常是)更有效的有關檢測已退出進程,並拋出異常。

特別地,當EnableRaisingEvents屬性被設置時,Process類寄存器由OS通知(經由線程池的RegisterWaitForSingleObject()方法)當處理句柄信號通知。即在這種情況下,Process類甚至不需要經過尋找主窗口句柄的努力,因爲幾乎立即通知該過程是否退出。

(當然,在一個非常小的機會窗口中仍然存在潛在的內部競爭條件,因爲當類別檢查已退出狀態時通知可能還沒有到達,但該過程可能仍然存在在Process類枚舉窗口之前退出)。

無論如何,這最後一點不會影響基本答案;這僅僅是我學到的一些小瑣事,在the Process source code遊蕩時發現有趣。 :)

+0

他們用enableraisingevents確實令人驚歎。 – victor