我正在尝试在 Linux Arm 设备上正常关闭我的控制台应用程序。发送的信号是SIGTERM
。我用新的实现了 Posix 信号处理程序PosixSignalRegistration.Create() https://learn.microsoft.com/en-us/dotnet/api/system.runtime.interopservices.posixsignalregistration.create?view=net-6.0方法。当在调试模式下编译时,这可以完美地工作。但是,在发布模式(打开优化)下,永远不会进入处理程序。
这是一个 MRE:
using Microsoft.Extensions.Hosting;
using System.Runtime.InteropServices;
ManualResetEvent resetEvent = new(false);
CancellationTokenSource cts = new();
// Handles CTRL + C in both operating systems
Console.CancelKeyPress += (sender, eventArgs) =>
{
Console.WriteLine("Received CTRL+C");
resetEvent.Set();
eventArgs.Cancel = true;
cts.Cancel();
};
// Handles graceful kill (Sigterm) in linux (e.g. systemctl stop)
PosixSignalRegistration.Create(PosixSignal.SIGTERM, (context) =>
{
Console.WriteLine("Received SIGTERM");
resetEvent.Set();
cts.Cancel();
});
IHost? host = null;
try
{
var hostBuilder = Host.CreateDefaultBuilder(args);
host = hostBuilder.Build();
host.Start();
resetEvent.Reset();
resetEvent.WaitOne();
}
catch
{
Console.WriteLine("Error");
}
finally
{
Console.WriteLine("finally");
await (host?.StopAsync(TimeSpan.FromSeconds(5)) ?? Task.CompletedTask);
Console.WriteLine("Application shut down");
}
在调试模式下,调用时pkill my-application -15
,日志如下所示,并且应用程序关闭:
Received SIGTERM
finally
info: Microsoft.Hosting.Lifetime[0]
Application is shutting down...
Application shut down
在发布模式下,唯一发生的事情是以下日志消息:
info: Microsoft.Hosting.Lifetime[0]
Application is shutting down...
然而,应用程序继续运行,只能通过以下方式正常关闭Ctrl + C
or pkill my-application -2
.
我缺少什么?
注意PosixSignalRegistration.Create
不返回 void,它返回一个实例PosixSignalRegistration
。该对象代表您的处理程序的注册,它实现IDisposable
并打电话Dispose
它将取消注册处理程序。它还具有终结器,其作用与 dispose - 取消注册处理程序相同。
现在请注意,您忽略了返回值PosixSignalRegistration.Create
。现在没有对上面提到的注册的引用,垃圾收集器可以自由地收集它。由于它有一个终结器 - 当 GC 收集实例时,它将被调用并且您的处理程序将被取消注册。
这就是你的情况发生的情况。在调试模式下,GC 不会出于各种原因(例如便于调试)收集它。然而,在发布模式下,它可以随时收集,甚至在发布后立即收集PosixSignalRegistration.Create
call.
你可能会添加GC.KeepAlive(yourRegistration)
在方法末尾调用,但在这种情况下这不是最好的主意,因为注册实现了IDisposable
所以你应该尊重这一点:
using (PosixSignalRegistration.Create(PosixSignal.SIGTERM, (context) => {
Console.WriteLine("Received SIGTERM");
resetEvent.Set();
cts.Cancel();
})) {
IHost? host = null;
try {
var hostBuilder = Host.CreateDefaultBuilder(args);
host = hostBuilder.Build();
host.Start();
resetEvent.Reset();
resetEvent.WaitOne();
}
catch {
Console.WriteLine("Error");
}
finally {
Console.WriteLine("finally");
await (host?.StopAsync(TimeSpan.FromSeconds(5)) ?? Task.CompletedTask);
Console.WriteLine("Application shut down");
}
}
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)