Using semaphore instead of while loop. Is this good or bad?

I have a process that starts its own thread in it and can be started / stopped without blocking. This will ultimately go into the Windows service, but now I configure it in the console application until it is completely hidden.

After calling Start (), I want the main program flow to be blocked until Ctrl-C is pressed. I know this will work:

public static void Main(string[] args) { bool keepGoing = true; var service = new Service(); System.Console.TreatControlCAsInput = false; System.Console.CancelKeyPress += delegate(object sender, ConsoleCancelEventArgs e) { e.Cancel = true; service.Stop(); keepGoing = false; // Break the while loop below }; service.Start(); while( keepGoing ) { Thread.Sleep(100); // 100 is arbitrary } } 

However, I believe that the flag and the arbitrary meaning of sleep are intrusive. I know that the cost of the processor is almost 0 during the while loop, but I would prefer to have a β€œhard” block that will be released as soon as the Ctrl-C handler is executed. I developed below using a semaphore to lock until an anonymous Ctrl-C handler is executed:

 public static void Main(string[] args) { var service = new Service(); var s = new Semaphore(1, 1); System.Console.TreatControlCAsInput = false; System.Console.CancelKeyPress += delegate(object sender, ConsoleCancelEventArgs e) { e.Cancel = true; service.Stop(); s.Release(); // This will allow the program to conclude below }; service.Start(); s.WaitOne(); // This will not block s.WaitOne(); // This will block w/o CPU usage until the sempahore is released } 

Is this a bad design? It's too much? This is dangerous?

EDIT:

I also attach AppDomain.CurrentDomain.UnhandledException as follows:

 AppDomain.CurrentDomain.UnhandledException += delegate { service.Stop(); s.Release(); }; 

EDIT 2nd:

I should note that it is very important that the Stop() method be called on exit. @Adam Ralph has a perfectly good hybrid console / service template, but did not have this information in Q's answer.

+6
source share
1 answer

We have a similar requirement in several of our applications. These are Windows services, but for debugging we often want to run them as console applications. Moreover, we usually code new applications as Windows services rather early, but often do not want them to actually launch them as a service until we have proved the concept, etc.

This is the template we use: -

 using (var service = new Service()) { if (Environment.UserInterActive) { service.Start(); Thread.Sleep(Timeout.Infinite); } else { ServiceBase.Run(service); } } 

Saying that the thread sleeps endlessly may seem inefficient, but this is only for debugging scenarios, and the excessive thread does not require processor time, but only memory (about 1 MB), which mainly consists of the stack space allocated for the thread. This process can still be displayed using Ctrl + C or closing the command window.

- EDIT -

If you find that service.Dispose() not called when you press Ctrl + C (i.e. a rough interruption occurs), and the call to Dispose() is crucial, then I think you could explicitly do it like this: -

 using (var service = new Service()) { if (Environment.UserInterActive) { Console.CancelKeyPress += (sender, e) => service.Dispose(); service.Start(); Thread.Sleep(Timeout.Infinite); } else { ServiceBase.Run(service); } } 

Note that Stop() should be encapsulated in Dispose() .

+4
source

Source: https://habr.com/ru/post/902859/


All Articles