Reputation: 2242
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
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
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
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
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
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
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
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
Reputation: 14331
Alternatively, a more simple solution is just:
Console.ReadLine();
Upvotes: 36
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