2009-07-29 86 views
2

C#.NET 3.5什麼是程序終止其自己的進程(Windows)中的正確方法

我有一個是由計算機上的其他應用程序中調用控制檯應用程序。該控制檯應用程序連續運行,並從「父」進程監聽stdin上的數據。

但是,當父母停止或死亡時,它啓動的控制檯應用程序將繼續。在正常情況下,它使用最少的資源坐着等待來自stdin的輸入。但是,一旦父母離開,該控制檯應用將觸發CPU,並以近100%的利用率捱餓運行的核心。這繼續下去,直到我手動殺死進程。

理想情況下,調用父母會自行清理,特別是因爲這是在正常(非常規)「停止」條件下發生的情況。不幸的是,這個父母過程不在我的手中。

我的第一個想法是從控制檯應用程序中獲取調用父級,並監控其PID。如果父進程消失,我的控制檯應用程序會自行終止。目前,我做這個:

Process process = Process.GetCurrentProcess(); 
m_ParentPID = 0; 
using (ManagementObject mgmtObj = new ManagementObject("win32_process.handle='" +  process.Id.ToString() + "'")) 
{ 
    mgmtObj.Get(); 
    m_ParentPID = Convert.ToInt32(mgmtObj["ParentProcessId"]); 
} 
string parentProcessName = Process.GetProcessById(m_ParentPID).ProcessName; 
Log("Parent Process: " + parentProcessName + Environment.NewLine); 

// Create a timer for monitoring self. 
Timer timer = new Timer(new TimerCallback(sender => 
{ 
    if (m_ParentPID != 0) 
    { 
     Process parent = System.Diagnostics.Process.GetProcessById(m_ParentPID); 
     if (parent == null) 
     { 
      Log("Parent process stopped/killed. Terminating self."); 
      System.Environment.Exit(0); 
     } 
    } 
})); 

// Kick on the timer 
timer.Change(m_ExitWatcherFrequency, m_ExitWatcherFrequency); 

這只是部分的工作雖然 - 它停止CPU峯值,但如果我看着Sysinternals公司的奇妙過程監控我的過程中,我可以看到DW20.exe運行中 - 「Microsoft應用程序錯誤報告」程序。它只是...坐在那裏,控制檯應用程序仍然在內存中。

我應該在這裏做些什麼來正確地終止這個過程,以避免這種連續的CPU峯值和未釋放的內存?最終這需要在沒有干預的情況下運行。

P.S.我在這裏使用命令行應用程序作爲「長時間運行的程序」而不是Windows服務或Web服務,因爲父程序只能配置爲執行命令行應用程序,通過stdin傳遞數據。 (對於那些好奇的人,這是ejabberd,使用外部認證)。

編輯:

是等待從標準輸入的代碼是:

// Read data from stdin 
char[] charray = new char[maxbuflen]; 
read = Console.In.Read(charray, 0, 2); 

我提到在此之前,當父終止,控制檯應用程序去瘋狂的CPU上。我在Visual Studio中附加了一個調試器,實際上它仍然在Console.In.Read中。理論上,當自監視計時器觸發並且看到父代已經消失時,它會在另一個線程位於該Read()行時嘗試System.Environment.Exit(0)。

回答

5

聽起來好像你的進程正在進入一個硬循環,因爲當父進程退出時控制檯輸入流被關閉。您是否在檢查Console.In.Read的回報值?當流關閉時它將返回零。在這一點上突破循環,讓你的Main()方法本身退出。

如果您正在運行多個線程,則必須先使用Thread.Join或同等工具完成。

3

要觀察過程出口,請使用Process類,並訂閱Exited事件。

編輯:刪除interop評論。

編輯(在響應評論):

大多數時候,是什麼在這樣的情況下完成的,是通過一些數據回來,這樣你就可以停止阻止在Console.In.Read方法調用。

因此,假設您在發現父進程完成後將標誌IsDone設置爲true。現在,因爲你等待的過程不再發送任何東西,你仍然需要接收標準輸入內容,否則你將永遠阻止。因此,在您的事件處理程序/計時器代碼中,將某些內容寫入您自己的進程的標準輸入(如果需要,它甚至可以是一個特殊的值,表示您已完成)。這會讓你通過Console.In.Read方法。一旦出來,檢查IsDone標誌是否已設置 - 如果是,請停止處理並從主方法返回 - 不需要System.Environment.Exit

+0

但是我該怎麼做一個程序終止自己,當它看到其他進程已退出?此外,我無法訪問父程序,因此我無法修改它以使它向孩子發送任何信號。 – Matt 2009-07-29 14:28:51

+0

您的控制檯應用程序如何等待輸入?某種循環?你可以發佈代碼(或僞代碼)嗎?這將有助於弄清楚最好的方法是什麼。 System.Environment.Exit(0)應該可以工作 - 所以我很好奇導致問題的原因。 – 2009-07-29 14:56:31

+0

更新的問題附有一些關於您的問題的附加信息,Nader – Matt 2009-07-29 15:08:40

2

我會通過向您的控制檯應用程序添加一個線程來解決此問題,該應用程序主要監視進程表中調用應用程序的存在。這是所有我的頭頂部,但這裏的一些僞代碼:

using System.Thread; 
using System.Diagnostics; 

main(){ 
    Thread monitoringThread = new Thread(new ThreadStart(monitor)); 
    monitoringThread.Name = "Monitor"; 
    monitoringThread.Start(); 
} 

和功能監控:

void monitor(){ 
    Process[] theCallers = Process.GetProcessesByName("CallingProcessName"); 
    theCallers[0].WaitForExit(); 
    Process.GetCurrentProcess().Kill(); 
} 

假設你只有一個調用進程在進程列表中,只要那個過程結束了,這個也會結束。你也可以爲你自己的過程提供更好的清理代碼,而不是讓它突然結束。

0

我喜歡mmr關注孩子父母過程的想法。如果您有辦法在命令行上傳遞父級的PID,那會更好。從父進程內部,你可以得到PID:

System.Diagnostics.Process.GetCurrentProcess().Id 
相關問題