2010-04-06 19 views
68

Considere una aplicación de consola que inicie algunos servicios en un hilo separado. Todo lo que tiene que hacer es esperar que el usuario presione Ctrl + C para apagarlo.¿Cómo mantener una aplicación de consola .NET ejecutándose?

¿Cuál de las siguientes es la mejor manera de hacer esto?

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 
} 

O esto, utilizando 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 
} 

Respuesta

41

siempre se quiere evitar el uso de bucles while, especialmente cuando estás forzando el código para volver a comprobar las variables. Desperdicia recursos de CPU y ralentiza su programa.

Definitivamente diré la primera.

+2

+1. Además, dado que 'bool' no está declarado como' volátil', existe la posibilidad definitiva de que las lecturas subsiguientes a '_quitFlag' en el bucle' while' se optimicen, lo que daría lugar a un ciclo infinito. –

20

Como alternativa, una solución más sencilla es simplemente:

Console.ReadLine(); 
+0

Estaba a punto de sugerir eso, pero no se detiene solo en Ctrl-C –

+0

Tengo la impresión de que CTRL-C fue solo un ejemplo: cualquier entrada de usuario para cerrarlo – Cocowalla

+0

Recuerde que 'Console.ReadLine()' es bloqueo de hiloEntonces la aplicación aún se estaría ejecutando pero sin hacer nada, salvo esperar a que el usuario ingrese una línea – fabriciorissetto

2

de los dos primeros uno es mejor

_quitEvent.WaitOne(); 

debido a que en el segundo el hilo se despierta cada un milisegundo será de llegar a convertirse en a la interrupción del sistema operativo que es caro

+0

Esta es una buena alternativa para los métodos 'Console' si no tengo una consola conectada (porque, por ejemplo, el programa es iniciado por un servicio) –

11

Puede hacerlo (y eliminar el controlador de eventos CancelKeyPress):

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

No estoy seguro de si es mejor, pero no me gusta la idea de llamar al Thread.Sleep en un bucle ... Creo que es más fácil bloquear la entrada del usuario.

+0

No me gusta que esté buscando las teclas Ctrl + C, en lugar de la señal activada por Ctrl + C. – CodesInChaos

0

Debería hacerlo como lo haría si estuviera programando un servicio de Windows. Nunca usarías una declaración while sino que usarías un delegado. WaitOne() se usa generalmente mientras se espera que los hilos se deshagan - Thread.Sleep() - no es aconsejable - ¿Ha pensado usar System.Timers.Timer usando ese evento para verificar el evento de apagado?

3

Parece que lo está haciendo más difícil de lo que necesita. ¿Por qué no solo Join el hilo después de haberle indicado que se detenga?

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

En mi caso, no controlo los hilos en los que se ejecuta el material asincrónico. – intoOrbit

+0

1) No me gusta que esté buscando las teclas Ctrl + C, en lugar de la señal activada por Ctrl + C. 2) Su enfoque no funciona si la aplicación usa Tareas en lugar de un solo hilo de trabajo. – CodesInChaos

8

Yo prefiero usar la Application.Run

static void Main(string[] args) { 

    //Do your stuff here 

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

    //Cleanup/Before Quit 
} 

a partir de los documentos:

comienza a funcionar un bucle de mensaje de aplicación estándar en el hilo actual, sin una forma.

+5

Pero luego toma una dependencia de los formularios de Windows solo para esto. No es demasiado problema con el framework .NET tradicional, pero la tendencia actual es hacia implementaciones modulares que incluyen solo las partes que necesita. – CodesInChaos

Cuestiones relacionadas