¿Cómo puedo capturar Ctrl+C (SIGINT) en una aplicación de consola C#?
Me gustaría poder capturar Ctrl+ Cen una aplicación de consola C# para poder realizar algunas limpiezas antes de salir. Cual es la mejor manera de hacer esto?
Para esto se utiliza el evento Console.CancelKeyPress . Así es como se usa:
public static void Main(string[] args)
{
Console.CancelKeyPress += delegate {
// call methods to clean up
};
while (true) {}
}
Cuando el usuario presiona Ctrl+, Cel código en el delegado se ejecuta y el programa sale. Esto le permite realizar la limpieza llamando a los métodos necesarios. Tenga en cuenta que no se ejecuta ningún código después de que se ejecute el delegado.
Hay otras situaciones en las que esto no es suficiente. Por ejemplo, si el programa está realizando cálculos importantes que no se pueden detener de inmediato. En ese caso, la estrategia correcta podría ser decirle al programa que salga una vez completado el cálculo. El siguiente código ofrece un ejemplo de cómo se puede implementar esto:
class MainClass
{
private static bool keepRunning = true;
public static void Main(string[] args)
{
Console.CancelKeyPress += delegate(object? sender, ConsoleCancelEventArgs e) {
e.Cancel = true;
MainClass.keepRunning = false;
};
while (MainClass.keepRunning) {
// Do your work in here, in small chunks.
// If you literally just want to wait until Ctrl+C,
// not doing anything, see the answer using set-reset events.
}
Console.WriteLine("exited gracefully");
}
}
La diferencia entre este código y el primer ejemplo es que e.Cancel
se establece en verdadero, lo que significa que la ejecución continúa después del delegado. Si se ejecuta, el programa espera a que el usuario presione Ctrl+ C. Cuando eso sucede, la keepRunning
variable cambia de valor, lo que hace que salga el ciclo while. Esta es una forma de hacer que el programa salga correctamente.
Ver MSDN:
Evento Console.CancelKeyPress
Artículo con ejemplos de código:
Ctrl-C y la aplicación de consola .NET
Me gustaría agregar algo a la respuesta de Jonas . Girar en a bool
provocará una utilización del 100% de la CPU y desperdiciará mucha energía sin hacer nada mientras se espera CTRL+ C.
La mejor solución es utilizar a ManualResetEvent
para "esperar" el CTRL+ C:
static void Main(string[] args) {
var exitEvent = new ManualResetEvent(false);
Console.CancelKeyPress += (sender, eventArgs) => {
eventArgs.Cancel = true;
exitEvent.Set();
};
var server = new MyServer(); // example
server.Run();
exitEvent.WaitOne();
server.Stop();
}
Aquí hay un ejemplo de trabajo completo. pegar en el proyecto de consola C# vacío:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading;
namespace TestTrapCtrlC {
public class Program {
static bool exitSystem = false;
#region Trap application termination
[DllImport("Kernel32")]
private static extern bool SetConsoleCtrlHandler(EventHandler handler, bool add);
private delegate bool EventHandler(CtrlType sig);
static EventHandler _handler;
enum CtrlType {
CTRL_C_EVENT = 0,
CTRL_BREAK_EVENT = 1,
CTRL_CLOSE_EVENT = 2,
CTRL_LOGOFF_EVENT = 5,
CTRL_SHUTDOWN_EVENT = 6
}
private static bool Handler(CtrlType sig) {
Console.WriteLine("Exiting system due to external CTRL-C, or process kill, or shutdown");
//do your cleanup here
Thread.Sleep(5000); //simulate some cleanup delay
Console.WriteLine("Cleanup complete");
//allow main to run off
exitSystem = true;
//shutdown right away so there are no lingering threads
Environment.Exit(-1);
return true;
}
#endregion
static void Main(string[] args) {
// Some biolerplate to react to close window event, CTRL-C, kill, etc
_handler += new EventHandler(Handler);
SetConsoleCtrlHandler(_handler, true);
//start your multi threaded program here
Program p = new Program();
p.Start();
//hold the console so it doesn’t run off the end
while (!exitSystem) {
Thread.Sleep(500);
}
}
public void Start() {
// start a thread and start doing some processing
Console.WriteLine("Thread started, processing..");
}
}
}