Coder Perfect

In a C# terminal app, how do I catch ctrl-c (SIGINT)?


are you doing this?

Asked by Nick Randell

Solution #1

For this, the Console.CancelKeyPress event is employed. This is how it is put to use:

public static void Main(string[] args)
    Console.CancelKeyPress += delegate {
        // call methods to clean up

    while (true) {}

The code in the delegate is run and the programme exits when the user pushes Ctrl + C. This allows you to clean up by invoking the appropriate procedures. There is no code after the delegate is run.

Other times, though, this will not enough. For instance, if the software is now executing critical calculations that cannot be interrupted immediately. In that scenario, telling the application to exit after the calculation is complete might be the best method. An example of how this can be done is shown in the code below:

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");

This code differs from the first in that e.Cancel is set to true, indicating that execution continues after the delegate. When the software is started, it waits for the user to press Ctrl + C. When this happens, the value of the keepRunning variable changes, causing the while loop to terminate. This is a method of politely exiting the program.

Answered by Jonas

Solution #2


Console.CancelKeyPress Event

Code samples are included in the article:

The.NET console program with Ctrl-C

Answered by aku

Solution #3

I’d like to add anything to Jonas’ response. Spinning on a bool will utilize 100% of the CPU and waste a lot of energy doing nothing while waiting for CTRL+C to be pressed.

The better solution is to use a ManualResetEvent to actually “wait” for the CTRL+C:

static void Main(string[] args) {
    var exitEvent = new ManualResetEvent(false);

    Console.CancelKeyPress += (sender, eventArgs) => {
                                  eventArgs.Cancel = true;

    var server = new MyServer();     // example


Answered by Jonathon Reinhart

Solution #4

Here’s a fully functional example. paste the following code into an empty C# console project:

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
        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

            return true;

        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();

            //hold the console so it doesn’t run off the end
            while (!exitSystem) {

        public void Start() {
            // start a thread and start doing some processing
            Console.WriteLine("Thread started, processing..");

Answered by JJ_Coder4Hire

Solution #5

This is a question that sounds a lot like:

Exit C# from the capture console

Here’s how I fixed the problem and dealt with the user pressing X and Ctrl-C at the same time. The use of ManualResetEvents is worth noting. These will put the main thread to sleep, allowing the CPU to focus on other tasks while the main thread waits for exit or cleanup. NOTE: At the end of main, you must set the TerminationCompletedEvent. Failure to do so results in unnecessary termination latency because the OS timeouts while stopping the application.

namespace CancelSample
    using System;
    using System.Threading;
    using System.Runtime.InteropServices;

    internal class Program
        /// <summary>
        /// Adds or removes an application-defined HandlerRoutine function from the list of handler functions for the calling process
        /// </summary>
        /// <param name="handler">A pointer to the application-defined HandlerRoutine function to be added or removed. This parameter can be NULL.</param>
        /// <param name="add">If this parameter is TRUE, the handler is added; if it is FALSE, the handler is removed.</param>
        /// <returns>If the function succeeds, the return value is true.</returns>
        private static extern bool SetConsoleCtrlHandler(ConsoleCloseHandler handler, bool add);

        /// <summary>
        /// The console close handler delegate.
        /// </summary>
        /// <param name="closeReason">
        /// The close reason.
        /// </param>
        /// <returns>
        /// True if cleanup is complete, false to run other registered close handlers.
        /// </returns>
        private delegate bool ConsoleCloseHandler(int closeReason);

        /// <summary>
        ///  Event set when the process is terminated.
        /// </summary>
        private static readonly ManualResetEvent TerminationRequestedEvent;

        /// <summary>
        /// Event set when the process terminates.
        /// </summary>
        private static readonly ManualResetEvent TerminationCompletedEvent;

        /// <summary>
        /// Static constructor
        /// </summary>
        static Program()
            // Do this initialization here to avoid polluting Main() with it
            // also this is a great place to initialize multiple static
            // variables.
            TerminationRequestedEvent = new ManualResetEvent(false);
            TerminationCompletedEvent = new ManualResetEvent(false);
            SetConsoleCtrlHandler(OnConsoleCloseEvent, true);

        /// <summary>
        /// The main console entry point.
        /// </summary>
        /// <param name="args">The commandline arguments.</param>
        private static void Main(string[] args)
            // Wait for the termination event
            while (!TerminationRequestedEvent.WaitOne(0))
                // Something to do while waiting

            // Sleep until termination

            // Print a message which represents the operation

            // Set this to terminate immediately (if not set, the OS will
            // eventually kill the process)

        /// <summary>
        /// Method called when the user presses Ctrl-C
        /// </summary>
        /// <param name="reason">The close reason</param>
        private static bool OnConsoleCloseEvent(int reason)
            // Signal termination

            // Wait for cleanup

            // Don't run other handlers, just exit.
            return true;

Answered by Paul

Post is based on