How to keep a .NET console app running?

C#MultithreadingSleepManualresetevent

C# Problem Overview


Consider a Console application that starts up some services in a separate thread. All it needs to do is wait for the user to press Ctrl+C to shut it down.

Which of the following is the better way to do this?

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
}

Or this, using 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
}

C# Solutions


Solution 1 - C#

you always want to prevent using while loops, especially when you are forcing the code to recheck variables. It wastes CPU resources and slows down your program.

I would definitely say the first one.

Solution 2 - C#

Alternatively, a more simple solution is just:

Console.ReadLine();

Solution 3 - C#

You can do that (and remove the CancelKeyPress event handler) :

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

Not sure if that's better, but I don't like the idea of calling Thread.Sleep in a loop.. I think it's cleaner to block on user input.

Solution 4 - C#

It's also possible to block the thread / program based on a cancellation token.

token.WaitHandle.WaitOne();

WaitHandle is signalled when the token is cancelled.

I have seen this technique used by the Microsoft.Azure.WebJobs.JobHost, where the token comes from a cancellation token source of the WebJobsShutdownWatcher (a file watcher that ends the job).

This gives some control over when the program can end.

Solution 5 - C#

I prefer using the Application.Run

static void Main(string[] args) {

   //Do your stuff here

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

   //Cleanup/Before Quit
}
     

from the docs: > Begins running a standard application message loop on the current thread, without a form.

Solution 6 - C#

Seems like you're making it harder than you need to. Why not just Join the thread after you've signaled it to stop?

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

Solution 7 - C#

Of the two first one is better

_quitEvent.WaitOne();

because in the second one the thread wakes up every one millisecond will get turned in to OS interrupt which is expensive

Solution 8 - C#

You should do it just like you would if you were programming a windows service. You would never use a while statement instead you would use a delegate. WaitOne() is generally used while waiting for threads to dispose - Thread.Sleep() - is not advisible - Have you thought of using System.Timers.Timer using that event to check for shut down event?

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionintoOrbitView Question on Stackoverflow
Solution 1 - C#MikeView Answer on Stackoverflow
Solution 2 - C#CocowallaView Answer on Stackoverflow
Solution 3 - C#Thomas LevesqueView Answer on Stackoverflow
Solution 4 - C#CRiceView Answer on Stackoverflow
Solution 5 - C#ygaradonView Answer on Stackoverflow
Solution 6 - C#Ed PowerView Answer on Stackoverflow
Solution 7 - C#NaveenView Answer on Stackoverflow
Solution 8 - C#KenLView Answer on Stackoverflow