프로그램이 자체 프로세스를 종료하는 올바른 방법은 무엇입니까 (Windows)

StackOverflow https://stackoverflow.com/questions/1200507

문제

C# .net 3.5

컴퓨터의 다른 응용 프로그램에서 호출되는 콘솔 응용 프로그램이 있습니다. 이 콘솔 앱은 지속적으로 실행되며 "부모"프로세스에서 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 Wantest Process Monitor에서 내 프로세스를 보면 DW20.exe가 실행되는 것을 볼 수 있습니다. 그리고 그것은 단지 ... 거기에 앉아 있고, 콘솔 앱은 메모리에 남아 있습니다.

이 연속 CPU 스파이크 및 미공개 메모리를 피하기 위해 프로세스를 올바르게 종료하기 위해 여기서 무엇을해야합니까? 결국 이것은 개입없이 달리기가 필요합니다.

추신 : 여기서 명령 줄 애플리케이션을 Windows 서비스 또는 웹 서비스 대신 "장기 실행 프로그램"으로 사용하고 있습니다. 부모 프로그램은 via stdin에서 데이터를 전달하는 명령 줄 앱을 실행하도록 구성 할 수 있기 때문입니다. (궁금한 사람들에게는 외부 인증을 사용하는 Ejabberd입니다).

편집하다:

stdin에서 입력을 기다리는 코드는 다음과 같습니다.

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

부모가 종료되면 콘솔 앱이 CPU에 미치게됩니다. 나는 Visual Studio에서 디버거를 첨부했으며 실제로는 여전히 그 라인 콘솔에 앉아 있습니다. 이론적으로, 자체 모니터링 타이머가 부모가 사라지는 것을 볼 때, 다른 스레드가 해당 read () 줄에있을 때 System.environment.exit (0)를 시도합니다.

도움이 되었습니까?

해결책

부모가 종료 할 때 콘솔 입력 스트림이 닫히기 때문에 프로세스가 하드 루프로 들어가는 것처럼 들립니다. 반환 값을 확인하고 있습니까? Console.In.Read? 스트림이 닫히면 0이 반환됩니다. 그 시점에서 루프에서 벗어나 Main() 메소드 종료 자체.

여러 스레드를 실행하는 경우 먼저 완료해야합니다. Thread.Join 또는 동등한.

다른 팁

프로세스 종료를 보려면 프로세스 수업을하고 구독하십시오 종료 이벤트.

편집 : interop 댓글이 제거되었습니다.

편집 (주석에 대한 응답) :

대부분의 경우, 이와 같은 상황에서 수행되는 일은 일부 데이터를 다시 전달하므로 차단을 중지 할 수 있습니다. Console.In.Read 방법 호출.

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

기본적으로 프로세스 테이블에서 호출 앱의 존재를 모니터링하는 콘솔 앱에 스레드를 추가하여이를 해결합니다. 이것은 모두 내 머리 꼭대기에서 벗어나지 만 여기에 일부 의사 코드가 있습니다.

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();
}

프로세스 목록에 하나의 호출 프로세스 만 있다고 가정하면 프로세스가 끝나 자마자이 프로세스도 마찬가지입니다. 당신은 또한 갑자기 끝나는 대신 자신의 프로세스에 훨씬 더 좋은 정리 코드를 넣을 수 있습니다.

나는 아이의 부모 과정을 보는 MMR의 아이디어를 좋아합니다. 명령 줄에서 부모의 PID를 전달할 수있는 방법이 있다면 더 나을 것입니다. 부모 프로세스 내부에서 PID를 얻을 수 있습니다.

System.Diagnostics.Process.GetCurrentProcess().Id
라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top