2010-04-06 19 views
68

Rozważ aplikację konsoli, która uruchamia niektóre usługi w osobnym wątku. Wystarczy, że poczekasz, aż użytkownik naciśnie Ctrl + C, aby go wyłączyć.Jak uruchomić aplikację konsoli .NET?

Który z poniższych sposobów jest lepszym sposobem?

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 
} 

Albo to, używając 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 
} 

Odpowiedz

41

zawsze chcesz, aby zapobiec użyciu pętli while, zwłaszcza gdy zmuszają kod, aby ponownie sprawdzić zmienne. To marnuje zasoby procesora i spowalnia twój program.

Zdecydowanie powiedziałbym pierwszy.

+2

+1. Ponadto, ponieważ 'bool' nie jest zadeklarowany jako' volatile', istnieje pewna możliwość, że późniejsze odczytywanie '_quitFlag' w pętli' while' będzie zoptymalizowane, prowadząc do nieskończonej pętli. –

20

Ewentualnie bardziej prostym rozwiązaniem jest po prostu:

Console.ReadLine(); 
+0

Chciałem to zasugerować, ale nie zatrzymam się tylko na Ctrl-C –

+0

Odniosłem wrażenie, że CTRL-C był tylko przykładem - każde wejście użytkownika, aby je zamknąć – Cocowalla

+0

Pamiętaj, że "Console.ReadLine()" jest blokowanie wątków.Tak więc aplikacja nadal będzie działać, ale nic nie robiąc, niż czekanie, aż użytkownik wejdzie w linię – fabriciorissetto

2

pierwszych dwóch z nich jest lepszy

_quitEvent.WaitOne(); 

ponieważ w drugim wątek budzi się każdy milisekundy dostanie zagrał do przerwania systemu operacyjnego, które jest drogie

+0

Jest to dobra alternatywa dla metod 'Console', jeśli nie ma podłączonej konsoli (ponieważ, na przykład, program jest uruchamiany przez usługę) –

11

Możesz to zrobić (i usunąć obsługę zdarzeń CancelKeyPress):

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

Nie jestem pewien, czy to jest lepsze, ale nie podoba mi się pomysł wywołania Thread.Sleep w pętli .. Myślę, że to czystsze, aby zablokować na dane wejściowe użytkownika.

+0

Nie podoba mi się, że sprawdzasz klawisze Ctrl + C, zamiast sygnału wyzwalanego przez Ctrl + C. – CodesInChaos

0

Powinieneś zrobić tak, jak zrobiłbyś, gdybyś programował usługę Windows. Nigdy nie używałbyś instrukcji while, zamiast używać delegata. WaitOne() jest zwykle używany podczas oczekiwania na wątki do usunięcia - Thread.Sleep() - nie jest zalecana - Czy myślałeś o użyciu System.Timers.Timer przy użyciu tego zdarzenia, aby sprawdzić wyłączenie zdarzenia?

3

Wygląda na to, że robisz to trudniej, niż potrzebujesz. Dlaczego nie po prostu Join wątek po sygnalizowaniu go zatrzymać?

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

W moim przypadku nie kontroluję wątków, na których działają elementy asynchroniczne. – intoOrbit

+0

1) Nie podoba mi się, że sprawdzasz klawisze Ctrl + C, zamiast sygnału wyzwalanego przez Ctrl + C. 2) Twoje podejście nie działa, jeśli aplikacja używa zadań zamiast pojedynczego wątku roboczego. – CodesInChaos

8

wolę pomocą Application.Run

static void Main(string[] args) { 

    //Do your stuff here 

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

    //Cleanup/Before Quit 
} 

z dokumentów:

Początek prowadzenie standardowej pętli wiadomość zastosowanie w obecnym wątku bez formy.

+5

Ale wtedy bierzesz zależność od formularzy Windows właśnie dla tego. Nie jest to zbyt duży problem z tradycyjną platformą .NET, ale obecny trend dotyczy modułowych wdrożeń obejmujących tylko te części, których potrzebujesz. – CodesInChaos

Powiązane problemy