检测控制台应用程序何时关闭/终止?
我想为我的控制台应用程序安全退出,该应用程序将使用单声道在linux上运行,但是我找不到一个解决方案来检测信号是否被发送到它或者用户按下了ctrl + c。
在Windows上有内核函数SetConsoleCtrlHandler,它可以完成这项工作但不能在单声道上工作。
如何在我的控制台应用程序上获得关闭事件以安全退出?
您需要使用Mono.UnixSignal
,Jonathan Pryor发布了一个很好的示例: http : Mono.UnixSignal
Mono页面上还有一个较短的示例: 常见问题/技术/操作系统问题/信号处理 :
// Catch SIGINT and SIGUSR1 UnixSignal[] signals = new UnixSignal [] { new UnixSignal (Mono.Unix.Native.Signum.SIGINT), new UnixSignal (Mono.Unix.Native.Signum.SIGUSR1), }; Thread signal_thread = new Thread (delegate () { while (true) { // Wait for a signal to be delivered int index = UnixSignal.WaitAny (signals, -1); Mono.Unix.Native.Signum signal = signals [index].Signum; // Notify the main thread that a signal was received, // you can use things like: // Application.Invoke () for Gtk# // Control.Invoke on Windows.Forms // Write to a pipe created with UnixPipes for server apps. // Use an AutoResetEvent // For example, this works with Gtk# Application.Invoke (delegate () { ReceivedSignal (signal); }); }});
作为提供unix和windows实现的示例,请参见下文。 请注意,使用Visual Studio时仍可以包含Mono.Posix dll。
我还添加了SIGTERM信号,因为当停止/重新启动应用程序作为服务时,unix中的systemd会触发此信号。
用于公开退出事件的接口
public interface IExitSignal { event EventHandler Exit; }
Unix实现
public class UnixExitSignal : IExitSignal { public event EventHandler Exit; UnixSignal[] signals = new UnixSignal[]{ new UnixSignal(Mono.Unix.Native.Signum.SIGTERM), new UnixSignal(Mono.Unix.Native.Signum.SIGINT), new UnixSignal(Mono.Unix.Native.Signum.SIGUSR1) }; public UnixExitSignal() { Task.Factory.StartNew(() => { // blocking call to wait for any kill signal int index = UnixSignal.WaitAny(signals, -1); if (Exit != null) { Exit(null, EventArgs.Empty); } }); } }
Windows实现
public class WinExitSignal : IExitSignal { public event EventHandler Exit; [DllImport("Kernel32")] public static extern bool SetConsoleCtrlHandler(HandlerRoutine Handler, bool Add); // A delegate type to be used as the handler routine // for SetConsoleCtrlHandler. public delegate bool HandlerRoutine(CtrlTypes CtrlType); // An enumerated type for the control messages // sent to the handler routine. public enum CtrlTypes { CTRL_C_EVENT = 0, CTRL_BREAK_EVENT, CTRL_CLOSE_EVENT, CTRL_LOGOFF_EVENT = 5, CTRL_SHUTDOWN_EVENT } /// /// Need this as a member variable to avoid it being garbage collected. /// private HandlerRoutine m_hr; public WinExitSignal() { m_hr = new HandlerRoutine(ConsoleCtrlCheck); SetConsoleCtrlHandler(m_hr, true); } /// /// Handle the ctrl types /// /// /// private bool ConsoleCtrlCheck(CtrlTypes ctrlType) { switch (ctrlType) { case CtrlTypes.CTRL_C_EVENT: case CtrlTypes.CTRL_BREAK_EVENT: case CtrlTypes.CTRL_CLOSE_EVENT: case CtrlTypes.CTRL_LOGOFF_EVENT: case CtrlTypes.CTRL_SHUTDOWN_EVENT: if (Exit != null) { Exit(this, EventArgs.Empty); } break; default: break; } return true; } }