【发布时间】:2011-12-01 19:18:49
【问题描述】:
我有一个进程在它自己的线程中运行,并且可以在没有阻塞的情况下启动/停止。这最终将进入 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 有一个非常好的混合控制台/服务模式,但在回答问题时没有此信息。
【问题讨论】:
-
如果你能避免while循环,我说它值得追求。
-
对于原型设计,后者是一个很大的改进。在生产应用程序中,我会避免整个“CTRL + C”中断想法。改为使用信号终止线程。信号
Set()的方式取决于所涉及的其他层。在设计服务时请记住这一点。添加一个方法,比如可以调用的方法,依次调用Set()。 -
@P.Brian.Mackey:虽然这不是一个生产应用程序,但如果它是,那么至少在非交互式控制台应用程序?实际上,Ctrl-C 将简单地关闭程序,而没有机会在退出前进行清理。最终,我只是想知道“while (flag) Thread.Sleep(...)”选项的信号量解决方案是否。
-
你可以用一个事件来做同样的事情。如果您在关闭之前等待多个线程,则信号量会更合适,这对于这种情况来说是多余的。一般来说,这是一个很好的做法 - 避免轮询。
-
我建议使用
ManualResetEvent而不是Semaphore。如果您必须跨进程通信,或者命名为EventWaitHandle。
标签: c# multithreading semaphore