使用信号量代替 while 循环。这是好是坏?
我有一个在它自己的线程中运行的进程,可以在不阻塞的情况下启动/停止。这最终将进入 Windows 服务,但我现在将其设置在控制台应用程序中,直到它完全充实为止。
调用 Start() 后,我希望主程序线程阻塞,直到按下 Ctrl-C。我知道这会起作用:
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
}
}
但是,我发现标志和任意睡眠值很麻烦。我知道 while 循环中的 CPU 成本几乎为 0,但我宁愿有一个“硬”块,它在 Ctrl-C 处理程序完成后立即释放。我设计了以下内容,使用信号量进行阻塞,直到匿名 Ctrl-C 处理程序完成:
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
}
这是一个糟糕的设计吗?是不是太过分了?危险吗?
编辑:
我还按如下方式连接AppDomain.CurrentDomain.UnhandledException:
AppDomain.CurrentDomain.UnhandledException += delegate {
service.Stop();
s.Release();
};
编辑第二个:
我应该注意,Stop()
退出时调用方法。 @Adam Ralph 对于混合控制台/服务有一个完美的模式,但在回答问题时没有这些信息。
I have a process that runs in it's own thread and can be started/stopped without blocking. This will eventually go into a Windows service, but I am setting this up in a console app for now until it is fully fleshed out.
After the call to Start(), I want the main program thread to block until Ctrl-C is pressed. I know that 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 find the flag and arbitrary sleep value bothersome. I know that the CPU cost is practically 0 in the while loop, but I'd rather have a "hard" block that releases as soon as the Ctrl-C handler is done. I devised the below, using a semaphore to block until the anonymous Ctrl-C handler is done:
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? Is it overkill? Is it dangerous?
EDIT:
I also hook up AppDomain.CurrentDomain.UnhandledException as follows:
AppDomain.CurrentDomain.UnhandledException += delegate {
service.Stop();
s.Release();
};
EDIT the 2nd:
I should note that it is crucial that the Stop()
method get called on exit. @Adam Ralph has a perfectly good pattern for a hybrid console/service, but didn't have this information when answering the Q.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
我们的一些应用程序也有类似的要求。它们是 Windows 服务,但为了调试,我们通常希望将它们作为控制台应用程序运行。此外,我们通常很早就将新应用程序编码为 Windows 服务,但通常不想将它们作为服务实际运行,直到稍后,一旦我们证明了概念等。
这是我们使用的模式:-
告诉无限休眠的线程可能看起来效率很低,但这仅适用于调试场景,并且冗余线程不消耗 CPU 时间,只消耗一些内存(大约 1MB),这些内存主要由分配给线程的堆栈空间组成。仍然可以使用 Ctrl+C 或关闭命令窗口来退出该进程。
-- 编辑 --
如果您发现按下 Ctrl+C 时未调用
service.Dispose()
(即发生粗鲁中止)并且调用Dispose()
code> 至关重要,那么我想你可以像这样显式地执行此操作: -请注意,
Stop()
应该封装在Dispose()
中。We have a similar requirement in a few of our apps. They are Windows services, but for debugging we often want to run them as console apps. Moreover, we usually code new apps as Windows services fairly early on but often don't want to have to actually run them as a service until later, once we've proved the concept, etc.
This is the pattern we use:-
Telling the thread to sleep infinitely might seem inefficient, but this is only for debugging scenarios and the redundant thread costs no CPU time, just some memory (about 1MB), which is mostly composed of the stack space allocated to the thread. The process can still be exited with Ctrl+C or by closing the command window.
-- EDIT --
If you find that
service.Dispose()
is not being called when Ctrl+C is pressed (i.e. a rude abort happens) and the call toDispose()
is crucial, then I guess you could explicitly do this like so:-Note that
Stop()
should be encapsulated inDispose()
.