intoOrbit
intoOrbit

Reputation: 2242

How to keep a .NET console app running?

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
}

Upvotes: 139

Views: 71772

Answers (9)

NizMaS
NizMaS

Reputation: 65

You may run as host

    public class Program
{
    /// <summary>
    /// Application entry point
    /// </summary>
    /// <param name="args">arguments</param>
    public static void Main(string[] args)
    {
        CreateHostBuilder(args).Build().Run();
    }

where HostBuilder is

    public static IHostBuilder CreateHostBuilder(string[] args) =>
        Host.CreateDefaultBuilder(args)
            .UseWindowsService()
            .ConfigureServices((_, services) =>
            {
            })
            .ConfigureLogging(config =>
            {
                config.ClearProviders();
            });

Upvotes: -1

CRice
CRice

Reputation: 12567

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.

Upvotes: 12

ygaradon
ygaradon

Reputation: 2298

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.

Upvotes: 9

Ed Power
Ed Power

Reputation: 8531

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

Upvotes: 4

KenL
KenL

Reputation: 875

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?

Upvotes: 0

Thomas Levesque
Thomas Levesque

Reputation: 292425

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.

Upvotes: 15

Naveen
Naveen

Reputation: 4110

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

Upvotes: 2

Cocowalla
Cocowalla

Reputation: 14331

Alternatively, a more simple solution is just:

Console.ReadLine();

Upvotes: 36

Mike
Mike

Reputation: 1492

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.

Upvotes: 85

Related Questions