2009-07-29 5 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 스파이크를 중지,하지만 난 시스 인 터널 멋진 프로세스 모니터에서 내 프로세스를 보면, 내가 인해 DW20.exe 실행을 볼 수 있습니다 - "Microsoft 응용 프로그램 오류보고"프로그램. 그리고 그저 거기 앉아서 콘솔 앱이 메모리에 남아 있습니다.

연속적인 CPU 스파이크 및 출시되지 않은 메모리를 방지하기 위해 프로세스를 올바르게 종료하려면 어떻게해야합니까? 결국 이것은 개입없이 실행되어야합니다.

P. 부모 프로그램은 stdin을 통해 데이터를 전달하는 명령 줄 앱만 실행하도록 구성 할 수 있기 때문에 여기서는 Windows 서비스 또는 웹 서비스 대신 "장기 실행 프로그램"으로 명령 줄 응용 프로그램을 사용하고 있습니다. (궁금한 사람들에게는 외부 인증을 사용하는 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에서 확인 하시겠습니까? 스트림이 닫 혔을 때 0을 반환합니다. 이 시점에서 루프에서 벗어나서 Main() 메서드를 종료하십시오.

여러 스레드를 실행중인 경우 먼저 Thread.Join 또는 동급을 사용하여 완료해야합니다.

+1

+1은 CPU 스파이크를 설명합니다 –

+0

흠, 좋은 점이 있습니다. 나는 CPU가 왜 스파이크를 일으키는 지 생각하기 위해 정말로 멈추지는 않았지만, Console.In.Read가 항상 0을 반환하기 때문에 지속적인 루프를 치는 것은 많은 의미를가집니다. – Matt

+0

여기에서주의해야 할 점은 정상 작동 중에 0 바이트가 반환되면 콘솔 앱이 제대로 종료되지 않는다는 것입니다. –

3

프로세스 종료를 감시하려면 Process 클래스를 사용하고 Exited 이벤트에 구독하십시오.

편집 : 삭제 된 interop 코멘트. (주석에 응답)

편집 :

대부분의 시간,이 같은 상황에서 이루어집니다 무엇을, 당신은 Console.In.Read 메서드 호출에 차단 중지 할 수 있도록, 다시 일부 데이터를 전달합니다.

따라서 부모 프로세스가 완료되었음을 발견하면 IsDone 플래그를 true로 설정한다고 가정합니다. 이제 대기중인 프로세스가 더 이상 아무것도 보내지 않을 것이기 때문에 표준 입력으로 뭔가를 받아야하거나 영원히 차단할 수 있습니다.따라서 이벤트 핸들러/타이머 코드에서 자신의 프로세스의 표준 입력에 무언가를 작성하십시오. 원하는 경우 완료되었음을 알리는 특수 값이 될 수도 있습니다. 그러면 Console.In.Read 메소드가 실행됩니다. 일단 밖으로, IsDone 플래그가 설정되어 있는지 확인하십시오 - 그렇다면, 처리를 중지하고 기본 방법에서 돌아 가기 - 아니 System.Environment.Exit 필요합니다.

+0

하지만 다른 프로세스가 종료 된 것으로 판단되면 프로그램을 종료하려면 어떻게해야합니까? 또한 부모 프로그램에 액세스 할 수 없으므로 자식에게 신호를 보내도록 수정할 수 없습니다. – Matt

+0

콘솔 앱이 입력을 얼마나 정확히 기다리고 있습니까? 어떤 종류의 루프? 코드 (또는 의사 코드)를 게시 할 수 있습니까? hte best approach가 무엇인지 파악하는 것이 유용 할 것입니다. System.Environment.Exit (0)이 작동해야합니다. 그래서 문제의 원인에 대해 궁금합니다. –

+0

귀하의 질문에 대한 몇 가지 추가 정보로 질문을 업데이트했습니다. Nader – Matt

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

본질적으로 위의 타이머()로 수행 한 작업이 아닌가요? (모니터링이 진행되는 한). Process.GetCurrentProcess(). Kill()은 System.Environment.Exit (0)과 어떻게 다릅니 까? – Matt

+0

이 솔루션은 시청 빈도가 없지만 프로세스가 종료되면 이벤트를 가져온 다음 나머지 스레드로 진행합니다. exit가 finalizers 등을 통과하는 동안 kill이 작동하기 때문에 Exit (0) 대신 Kill()을 사용했습니다. 파이널 라이저에 신경 쓰지 않는다면 kill은 괜찮을 것이지만 청소를 원할 경우 exit (0)가 더 좋습니다. 그러나, 귀하의 처리 스파이크의 원인이 finalizers 수 있습니다, 잘 모르겠습니다. – mmr

+0

아, 무슨 뜻인지 알 겠어. 따라서 존재하지 않는 프로세스를 폴링하는 대신 출구를 기다리는 또 다른 스레드가 있습니다. – Matt

0

나는 부모 프로세스를 아이에게서보고 있다는 mmr의 아이디어가 마음에 든다. 부모의 PID를 명령 줄에 전달하는 방법이 있다면 더 좋을 것입니다. 상위 프로세스 내부에서 PID를 얻을 수 있습니다 :

System.Diagnostics.Process.GetCurrentProcess().Id 
+0

부모를 수정할 수 없다. –