[英]How to keep a .NET console app running?
考虑一个在单独线程中启动某些服务的控制台应用程序。 它所需要做的就是等待用户按 Ctrl+C 将其关闭。
以下哪项是执行此操作的更好方法?
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
}
或者这个,使用 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
}
您总是想避免使用while循环,尤其是在强制代码重新检查变量时。 这会浪费CPU资源并减慢程序速度。
我肯定会说第一个。
另外,一个更简单的解决方案是:
Console.ReadLine();
您可以执行此操作(并删除CancelKeyPress
事件处理程序):
while(!_quitFlag)
{
var keyInfo = Console.ReadKey();
_quitFlag = keyInfo.Key == ConsoleKey.C
&& keyInfo.Modifiers == ConsoleModifiers.Control;
}
不知道这是否更好,但是我不喜欢在循环中调用Thread.Sleep
的想法。我认为阻止用户输入会更干净。
我更喜欢使用Application.Run
static void Main(string[] args) {
//Do your stuff here
System.Windows.Forms.Application.Run();
//Cleanup/Before Quit
}
从文档:
开始在当前线程(没有表单)上运行标准应用程序消息循环。
似乎您正在使它变得比所需的更难。 为什么在发出停止信号后不只是Join
线程?
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);
}
}
}
前两个比较好
_quitEvent.WaitOne();
因为在第二个线程中,线程每隔一毫秒唤醒一次,就会进入OS中断,这很昂贵
您应该像对Windows服务进行编程一样进行操作。 您永远不会使用while语句,而会使用委托。 通常在等待线程处理时使用WaitOne()-Thread.Sleep()-不可见-您是否考虑过使用System.Timers.Timer使用该事件来检查关闭事件?
也可以基于取消令牌来阻止线程/程序。
token.WaitHandle.WaitOne();
当令牌被取消时,会发出WaitHandle信号。
我已经看到Microsoft.Azure.WebJobs.JobHost使用的这项技术,其中的令牌来自WebJobsShutdownWatcher(结束工作的文件监视程序)的取消令牌源。
这可以控制何时可以结束程序。
您可以作为主机运行
public class Program
{
/// <summary>
/// Application entry point
/// </summary>
/// <param name="args">arguments</param>
public static void Main(string[] args)
{
CreateHostBuilder(args).Build().Run();
}
HostBuilder 在哪里
public static IHostBuilder CreateHostBuilder(string[] args) =>
Host.CreateDefaultBuilder(args)
.UseWindowsService()
.ConfigureServices((_, services) =>
{
})
.ConfigureLogging(config =>
{
config.ClearProviders();
});
我们可以等待应用程序内部抛出的任何异常,而不是读取Console.ReadKey()
。
program.cs 看起来像
例如:
class Program
{
static ManualResetEvent _quitEvent = new ManualResetEvent(false);
static async Task Main(string[] args)
{
AppDomain currentDomain = AppDomain.CurrentDomain;
currentDomain.UnhandledException += new UnhandledExceptionEventHandler(UnhandledExceptionHandler);
// code to start the App
//
_quitEvent.WaitOne();
}
static void UnhandledExceptionHandler(object sender, UnhandledExceptionEventArgs args)
{
Exception e = (Exception) args.ExceptionObject;
logger.Error("APP faulted!! " + e.ToString());
System.Threading.Thread.Sleep(1000);
_quitEvent.Set();
}
}
在这种情况下,如果要停止应用程序,则必须终止该应用程序。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.