Chr*_*ons 6 c# multithreading semaphore
我有一个在它自己的线程中运行的进程,可以在不阻塞的情况下启动/停止.这将最终进入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
}
}
Run Code Online (Sandbox Code Playgroud)
但是,我发现标志和任意睡眠值令人烦恼.我知道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
}
Run Code Online (Sandbox Code Playgroud)
这是一个糟糕的设计吗?这有点矫枉过正吗?危险吗?
编辑:
我还挂钩了AppDomain.CurrentDomain.UnhandledException,如下所示:
AppDomain.CurrentDomain.UnhandledException += delegate {
service.Stop();
s.Release();
};
Run Code Online (Sandbox Code Playgroud)
编辑第二个:
我应该注意,Stop()在退出时调用该方法至关重要.@Adam Ralph对于混合控制台/服务有一个非常好的模式,但在回答Q时没有这个信息.
我们的一些应用程序也有类似的要求。它们是 Windows 服务,但为了调试,我们通常希望将它们作为控制台应用程序运行。此外,我们通常很早就将新应用程序编码为 Windows 服务,但通常不想将它们作为服务实际运行,直到稍后,一旦我们证明了这个概念等。
这是我们使用的模式:-
using (var service = new Service())
{
if (Environment.UserInterActive)
{
service.Start();
Thread.Sleep(Timeout.Infinite);
}
else
{
ServiceBase.Run(service);
}
}
Run Code Online (Sandbox Code Playgroud)
让线程无限休眠似乎效率低下,但这仅适用于调试场景,并且冗余线程不消耗 CPU 时间,只消耗一些内存(大约 1MB),这些内存主要由分配给线程的堆栈空间组成。仍然可以使用 Ctrl+C 或关闭命令窗口来退出该进程。
- 编辑 -
如果您发现service.Dispose()按下 Ctrl+C 时没有调用(即发生粗鲁中止)并且调用Dispose()至关重要,那么我想您可以像这样显式地执行此操作:-
using (var service = new Service())
{
if (Environment.UserInterActive)
{
Console.CancelKeyPress += (sender, e) => service.Dispose();
service.Start();
Thread.Sleep(Timeout.Infinite);
}
else
{
ServiceBase.Run(service);
}
}
Run Code Online (Sandbox Code Playgroud)
注意Stop()应该封装在Dispose().
| 归档时间: |
|
| 查看次数: |
1528 次 |
| 最近记录: |