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:

  1. You're missing a myThread.Join().

    ReplyDelete
  2. Anonymous10:32 am

    nice one...

    ReplyDelete
  3. Anonymous5:53 pm

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

    ReplyDelete
  4. Patrik Svensson12:25 pm

    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

    ReplyDelete
  5. Just in case if someone prefers task-based version:

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

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

    ReplyDelete
  7. Thanks Konstantin. Task based version is very nice :)

    ReplyDelete
  8. Anonymous1:01 pm

    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

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

    ReplyDelete

Note: only a member of this blog may post a comment.