.NET 콘솔 앱을 계속 실행하는 방법은 무엇입니까?


105

별도의 스레드에서 일부 서비스를 시작하는 콘솔 애플리케이션을 고려하십시오. 사용자가 Ctrl + C를 눌러 종료 할 때까지 기다리기만하면됩니다.

다음 중이 작업을 수행하는 더 좋은 방법은 무엇입니까?

static ManualResetEvent _quitEvent = new ManualResetEvent(false);

static void Main() {
    Console.CancelKeyPress += (sender, eArgs) => {
        _quitEvent.Set();
        eArgs.Cancel = true;
    };

    // kick off asynchronous stuff 

    _quitEvent.WaitOne();

    // cleanup/shutdown and quit
}

또는 Thread.Sleep (1) 사용 :

static bool _quitFlag = false;

static void Main() {
    Console.CancelKeyPress += delegate {
        _quitFlag = true;
    };

    // kick off asynchronous stuff 

    while (!_quitFlag) {
        Thread.Sleep(1);
    }

    // cleanup/shutdown and quit
}

답변:


64

특히 코드에서 변수를 다시 확인하도록 할 때 항상 while 루프를 사용하지 않으려 고합니다. CPU 리소스를 낭비하고 프로그램 속도를 늦 춥니 다.

나는 확실히 첫 번째를 말할 것입니다.


2
+1. bool또한는로 선언되지 않았기 때문에 루프 에서 volatile후속 읽기 가 최적화되어 무한 루프로 이어질 가능성 이 있습니다. _quitFlagwhile
Adam Robinson

2
이를 수행하는 권장 방법이 없습니다. 나는 이것을 대답으로 기대하고 있었다.
Iúri dos Anjos apr

30

또는 더 간단한 솔루션은 다음과 같습니다.

Console.ReadLine();

제가 제안하려고했지만 Ctrl-C에서만 멈추지 않을 것입니다
Thomas Levesque

내가 CTRL-C는 단지 예라고 인상을 가지고 - 사용자의 입력을 닫습니다
Cocowalla

'Console.ReadLine ()'은 스레드 차단이라는 것을 기억하십시오. 따라서 응용 프로그램은 계속 실행되지만 사용자가 줄을 입력하기를 기다리는 것 외에는 아무것도하지 않습니다
fabriciorissetto

2
@fabriciorissetto OP 질문에 '비동기 작업 시작'이 명시되어 있으므로 응용 프로그램은 다른 스레드에서 작업을 수행합니다
Cocowalla

1
@Cocowalla 나는 그것을 놓쳤다. 내 잘못이야!
fabriciorissetto

12

그렇게 할 수 있습니다 (그리고 CancelKeyPress이벤트 핸들러를 제거하십시오 ).

while(!_quitFlag)
{
    var keyInfo = Console.ReadKey();
    _quitFlag = keyInfo.Key == ConsoleKey.C
             && keyInfo.Modifiers == ConsoleModifiers.Control;
}

그게 더 좋은지는 모르겠지만 Thread.Sleep루프에서 호출한다는 생각이 마음에 들지 않습니다 . 사용자 입력을 차단하는 것이 더 깔끔하다고 생각합니다.


Ctrl + C로 트리거되는 신호 대신 Ctrl + C 키를 확인하는 것이 마음에 들지 않습니다.
CodesInChaos

9

나는 Application.Run을 사용하는 것을 선호합니다.

static void Main(string[] args) {

   //Do your stuff here

   System.Windows.Forms.Application.Run();

   //Cleanup/Before Quit
}

문서에서 :

양식없이 현재 스레드에서 표준 응용 프로그램 메시지 루프 실행을 시작합니다.


10
그러나 당신은 이것을 위해 윈도우 폼에 의존합니다. 기존 .NET 프레임 워크의 문제는 그리 크지 않지만 현재 추세는 필요한 부분 만 포함하는 모듈 식 배포입니다.
CodesInChaos 2015 년

4

필요한 것보다 더 어렵게 만드는 것 같습니다. Join중지하라는 신호를 보낸 후 스레드가 아닌 이유는 무엇 입니까?

class Program
{
    static void Main(string[] args)
    {
        Worker worker = new Worker();
        Thread t = new Thread(worker.DoWork);
        t.IsBackground = true;
        t.Start();

        while (true)
        {
            var keyInfo = Console.ReadKey();
            if (keyInfo.Key == ConsoleKey.C && keyInfo.Modifiers == ConsoleModifiers.Control)
            {
                worker.KeepGoing = false;
                break;
            }
        }
        t.Join();
    }
}

class Worker
{
    public bool KeepGoing { get; set; }

    public Worker()
    {
        KeepGoing = true;
    }

    public void DoWork()
    {
        while (KeepGoing)
        {
            Console.WriteLine("Ding");
            Thread.Sleep(200);
        }
    }
}

2
제 경우에는 비동기 작업이 실행되는 스레드를 제어하지 않습니다.
intoOrbit 2010

1) Ctrl + C로 트리거되는 신호 대신 Ctrl + C 키를 확인하는 것이 마음에 들지 않습니다. 2) 애플리케이션이 단일 작업자 스레드 대신 작업을 사용하는 경우 접근 방식이 작동하지 않습니다.
CodesInChaos 2015 년

2

취소 토큰을 기반으로 스레드 / 프로그램을 차단할 수도 있습니다.

token.WaitHandle.WaitOne();

WaitHandle은 토큰이 취소되면 신호를 보냅니다.

Microsoft.Azure.WebJobs.JobHost에서이 기술을 사용하는 것을 보았습니다. 여기서 토큰은 WebJobsShutdownWatcher (작업을 종료하는 파일 감시자)의 취소 토큰 소스에서 가져옵니다.

이것은 프로그램이 언제 종료 될 수 있는지에 대한 제어를 제공합니다.


1
이것은 CTL+C오래 실행되는 작업을 수행하고 있거나 작업자 스레드를 정상적으로 종료해야하는 데몬이기 때문에 수신해야하는 실제 콘솔 앱에 대한 훌륭한 대답입니다 . CancelToken으로 그렇게 할 수 있으므로이 답변은 새 토큰을 WaitHandle만드는 대신 이미 존재 하는 을 활용 합니다.
mdisibio

1

첫 번째 두 개 중 하나가 더 좋습니다

_quitEvent.WaitOne();

두 번째에서 스레드는 매 1 밀리 초마다 깨어나 기 때문에 비용이 많이 드는 OS 인터럽트로 전환됩니다.


Console콘솔이 연결되어 있지 않은 경우 (예 : 프로그램이 서비스에 의해 시작되기 때문에) 방법에 대한 좋은 대안입니다.
Marco Sulla

0

Windows 서비스를 프로그래밍 할 때와 똑같이해야합니다. while 문을 사용하지 않고 대신 대리자를 사용합니다. WaitOne ()은 일반적으로 스레드가 처리 될 때까지 기다리는 동안 사용됩니다.-Thread.Sleep ()-권장되지 않습니다.-종료 이벤트를 확인하기 위해 해당 이벤트를 사용하는 System.Timers.Timer를 사용하는 것을 고려해 보셨습니까?

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.