2011-12-01 1 views
6

나는 자체 스레드에서 실행되는 프로세스를 가지고 있으며 차단하지 않고 시작/중지 할 수 있습니다. 이것은 결국 Windows 서비스로 들어갈 것이지만, 지금까지 콘솔 앱에서이 기능을 설정하고 있습니다.while 루프 대신 세마포어 사용. 이게 좋은 일입니까 나쁜 일입니까?

Start() 호출 후 Ctrl-C를 누를 때까지 주 프로그램 스레드를 차단하고 싶습니다. 나는이 일 것이라는 점을 알고있다 :

public static void Main(string[] args) 
{ 
    bool keepGoing = true; 

    var service = new Service(); 

    System.Console.TreatControlCAsInput = false; 

    System.Console.CancelKeyPress += delegate(object sender, ConsoleCancelEventArgs e) 
    { 
     e.Cancel = true; 
     service.Stop(); 
     keepGoing = false; // Break the while loop below 
    }; 

    service.Start(); 

    while(keepGoing) 
    { 
     Thread.Sleep(100); // 100 is arbitrary 
    } 

} 

그러나, 나는 플래그와 임의의 수면 값이 귀찮은 찾을 수 있습니다. 나는 while 루프에서 CPU 비용이 거의 0이라는 것을 알고 있지만, Ctrl-C 핸들러가 끝나자 마자 "하드"블록을 릴리스하고 싶습니다. 나는 익명의 Ctrl-C 처리기가 완료 될 때까지 차단하기 위해 세마포어를 사용하여 아래를 고안했다 :

public static void Main(string[] args) 
{ 
    var service = new Service(); 

    var s = new Semaphore(1, 1); 

    System.Console.TreatControlCAsInput = false; 

    System.Console.CancelKeyPress += delegate(object sender, ConsoleCancelEventArgs e) 
    { 
     e.Cancel = true; 
     service.Stop(); 
     s.Release(); // This will allow the program to conclude below 
    }; 

    service.Start(); 

    s.WaitOne(); // This will not block 
    s.WaitOne(); // This will block w/o CPU usage until the sempahore is released 

} 

이것은 잘못된 설계인가? 과잉인가요? 위험한가요?

편집 : 2

AppDomain.CurrentDomain.UnhandledException += delegate { 
    service.Stop(); 
    s.Release(); 
}; 

편집 : 다음과 같이 나 또한 AppDomain.CurrentDomain.UnhandledException를 연결

는 그 중요한

내가주의해야한다입니다 출구에서 Stop() 메서드가 호출됩니다. @Adam Ralph는 하이브리드 콘솔/서비스에 대한 완벽한 패턴을 가지고 있지만 Q에 대답 할 때이 정보가 없습니다.

+1

while 루프를 피할 수만 있다면 그럴만 한 가치가 있다고 말합니다. – ChaosPandion

+1

프로토 타이핑을 위해서는 후자가 많이 개선되었습니다. 프로덕션 응용 프로그램에서 나는 전체 "CTRL + C"중단 생각을 피할 것입니다. 대신 스레드를 죽이기 위해 신호를 사용하십시오. 신호가'Set()'인 방식은 관련된 다른 레이어에 달려 있습니다. 서비스를 설계 할 때이를 명심하십시오. 'Set()'을 호출 할 수있는 메소드와 같은 수단을 추가하십시오. –

+0

@ P.Brian.Mackey :이 프로그램은 프로덕션 애플리케이션이 아니지만 * * 인 경우 비대화 형 콘솔 앱에서 Ctrl-C를 정상적으로 처리하는 것이 현명하지 않습니까? 그대로, Ctrl-C는 종료하기 전에 정리할 기회없이 단순히 프로그램을 종료합니다. 궁극적으로, 나는 단순히 "while (flag) Thread.Sleep (...)"옵션에 대한 세마포어 솔루션인지 궁금합니다. –

답변

4

우리는 몇 가지 응용 프로그램에서 비슷한 요구 사항을 가지고 있습니다. 그것들은 Windows 서비스이지만, 디버깅을 위해 종종 콘솔 앱으로 실행하려고합니다. 또한, 우리는 보통 비교적 초기에 Windows 서비스로 새로운 앱을 코딩하지만 나중에 컨셉을 입증하면 나중에 실제로 서비스로 실행해야하는 것을 원하지 않는 경우가 종종 있습니다.

사용 : -

using (var service = new Service()) 
{ 
    if (Environment.UserInterActive) 
    { 
     service.Start(); 
     Thread.Sleep(Timeout.Infinite); 
    } 
    else 
    { 
     ServiceBase.Run(service); 
    } 
} 

무한 잠을 스레드를 말하는 비효율적 보일 수도 있지만, 이것은 디버깅 시나리오 만하고 중복 스레드가 주로 구성되어있다 (약 1MB), 그냥 메모리를 더 CPU 시간을 비용이 없습니다 스레드에 할당 된 스택 공간 프로세스는 여전히 Ctrl + C 또는 명령 창을 닫아 종료 할 수 있습니다.

- 편집 - (무례한 중단이 발생 예)와 Dispose()에 대한 호출이 매우 중요합니다 당신은 Ctrl + C를 누를 때 service.Dispose()가 호출되지 않는 것으로 확인되면

, 나는 당신이 명시 적으로 할 수있는 것 같아요 이 같은 : - Stop()Dispose()에 캡슐화되어야한다고

using (var service = new Service()) 
{ 
    if (Environment.UserInterActive) 
    { 
     Console.CancelKeyPress += (sender, e) => service.Dispose(); 
     service.Start(); 
     Thread.Sleep(Timeout.Infinite); 
    } 
    else 
    { 
     ServiceBase.Run(service); 
    } 
} 

참고.

+0

'UserInterActive' 컨텍스트에서 사용자가 (Ctrl-C 또는 창 닫기를 사용하여) 프로세스를 중지하려고 시도하는 경우'Stop()'메서드가 호출되지 않는 문제가 여전히 발생하지 않습니다 ? 이것이 내가 위의 예에서 성취하려고하는 것입니다. –

+0

우리의 서비스에서 Stop 메서드를 호출하는 것은 중요하지 않지만 여전히 CancelKeyPress에 가입하여 명시 적으로 할 수 있다고 생각합니다. 나는 대답을 편집 할 것이다 –

+0

Q에 이것에 관해 명확하지 않았다. 그 죄송합니다. 나는 이것에 대해 언급했다. –

관련 문제