2011-07-01 14 views
18

Tôi muốn thoát an toàn cho ứng dụng bảng điều khiển sẽ chạy trên linux bằng cách sử dụng mono nhưng tôi không thể tìm thấy giải pháp để phát hiện tín hiệu được gửi đến nó hoặc người dùng nhấn ctrl + c.Phát hiện khi ứng dụng bảng điều khiển đóng/bị giết?

Trên cửa sổ có chức năng hạt nhân SetConsoleCtrlHandler thực hiện công việc nhưng điều đó không hoạt động trên đơn âm.

Làm cách nào để có sự kiện đóng trên ứng dụng bảng điều khiển của tôi để thoát an toàn?

Trả lời

11

Bạn cần phải sử dụng Mono.UnixSignal, có một mẫu tốt đăng bởi Jonathan Pryor: http://www.jprl.com/Blog/archive/development/mono/2008/Feb-08.html

Ngoài ra còn có một ví dụ ngắn trên trang Mono: FAQ/Technical/Operating System Questions/Signal Handling:

// 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); }); 
    }}); 
+0

và cách thức invoke sẽ trông như thế cho một ứng dụng giao diện điều khiển? Bạn đang thiếu một} trong khi – Prix

+0

Tôi không thể tìm thấy Mono.Posix để tham khảo về dự án của tôi, bạn có thể cho tôi một số hướng dẫn thêm về vấn đề này ... cả hai liên kết là rất không đầy đủ;/ – Prix

+1

@Prix: Mono.Posix .dll được cài đặt bởi trình cài đặt Mono 2.10.2 tiêu chuẩn, bạn đang sử dụng phân phối nào? Ngoài ra, đối với một ứng dụng giao diện điều khiển, bạn có thể bỏ qua 'Application.Invoke' và chỉ cần gọi logic dọn dẹp từ chuỗi tín hiệu. – skolima

7

Như một ví dụ về việc cung cấp một unix và cửa sổ thực hiện xem dưới đây. Lưu ý rằng bạn vẫn có thể bao gồm dll Mono.Posix khi sử dụng Visual Studio.

Tôi cũng đã thêm tín hiệu SIGTERM vì điều này được kích hoạt bởi systemd trong Unix khi dừng/khởi động lại ứng dụng của bạn dưới dạng dịch vụ.

Interface để lộ một sự kiện xuất cảnh thực hiện

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); 
      } 

     }); 
    } 

} 

của Windows thực hiện

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 
    } 

    /// <summary> 
    /// Need this as a member variable to avoid it being garbage collected. 
    /// </summary> 
    private HandlerRoutine m_hr; 

    public WinExitSignal() 
    { 
     m_hr = new HandlerRoutine(ConsoleCtrlCheck); 

     SetConsoleCtrlHandler(m_hr, true); 

    } 

    /// <summary> 
    /// Handle the ctrl types 
    /// </summary> 
    /// <param name="ctrlType"></param> 
    /// <returns></returns> 
    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; 
    } 


} 
+0

Lưu ý rằng tôi đã gặp sự cố với Task.Factory.StartMới có vẻ như đã được khắc phục bằng một luồng nền chuyên dụng (trong khi đang sử dụng mono trong bộ chứa docker); Đã có người khác gặp phải điều này? –