Monday, April 22, 2013

Stop Your Console App The Nice Way

When you write a console application, do you simply put

Console.WriteLine("Hit <enter> to end");
Console.ReadLine();

at the end of Main and block on Console.ReadLine()?

It’s much nicer to to make your console application work with Windows command line conventions and exit when the user types Control-C.

The Console class has a static event CancelKeyPress that fires when Ctrl-C is pressed. You can create an AutoResetEvent that blocks until you call Set in the CancelKeyPress handler.

It’s also nice to stop the application from being arbitrarily killed at the point where Ctrl-C is pressed by setting the EventArgs.Cancel property to true. This gives you a chance to complete what you are doing and exit the application cleanly.

Here’s an example. My little console application kicks off a worker thread and then blocks waiting for Ctrl-C as described above. When Ctrl-C is pressed I send a signal to the worker thread telling it to finish what it’s doing and exit.

using System;
using System.Threading;

namespace Mike.Spikes.ConsoleShutdown
{
class Program
{
private static bool cancel = false;

static void Main(string[] args)
{
Console.WriteLine("Application has started. Ctrl-C to end");

// do some cool stuff here
var myThread = new Thread(Worker);
myThread.Start();

var autoResetEvent = new AutoResetEvent(false);
Console.CancelKeyPress += (sender, eventArgs) =>
{
// cancel the cancellation to allow the program to shutdown cleanly
eventArgs.Cancel = true;
autoResetEvent.Set();
};

// main blocks here waiting for ctrl-C
autoResetEvent.WaitOne();
cancel = true;
Console.WriteLine("Now shutting down");
}

private static void Worker()
{
while (!cancel)
{
Console.WriteLine("Worker is working");
Thread.Sleep(1000);
}
Console.WriteLine("Worker thread ending");
}
}
}

Much nicer I think.

9 comments:

Roger Lipscombe said...

You're missing a myThread.Join().

Anonymous said...

nice one...

Anonymous said...

This is how Workflow Console Applications run in .NET Framework 3.5. Nevertheless, a useful post. Thanks.

Patrik Svensson said...

There is a bug in the .NET framework 4 for Console.CancelKeyPress that crashes the application if the debugger is attached. http://connect.microsoft.com/VisualStudio/feedback/details/524889/debugging-c-console-application-that-handles-console-cancelkeypress-is-broken-in-net-4-0

Konstantin Savelev said...

Just in case if someone prefers task-based version:

https://gist.github.com/ksavelev/5473522

Andrei Rinea said...

So several more lines of code is better than two?!

Mike Hadlow said...

Thanks Konstantin. Task based version is very nice :)

Teo T said...

Very interesting tip! I work for a new social blogging site called glipho.com, and was just wondering if you would be interested in sharing your posts there with us? It wouldn't affect your blog in any way, and I know there are many aspiring programmers withing our community who would love to read through your work here. Let me know what you think!

All the best,

Teo

Michael said...

What about something like this?
https://gist.github.com/mayvazyan/5554325