這是一個建立於 的文章,其中的資訊可能已經有所發展或是發生改變。
http://m.oschina.net/blog/125853
如果是命令列程式需要退出, CTRL+C
是最直接的方法.
C語言如何處理CTRL+C
CTRL+C
會向命令列進程發送中斷訊號, 在C語言的<signal.h>
中的signal
函數可以註冊訊號的處理函數.
signal
函數的簽名如下:
void (*signal(int sig, void (*func)(int)))(int);
比如, 我們要處理CTRL+C
對應的SIGINT
訊號:
#include <stdio.h>#include <stdlib.h>#include <signal.h>void sigHandle(int sig) { switch(sig) { case SIGINT: printf("sigHandle: %d, SIGINT\n", sig); break; default: printf("sigHandle: %d, OTHER\n", sig); break; } exit(1);}int main() { signal(SIGINT, sigHandle); for(;;) {} return 0;}
編譯並運行程式後會進入死迴圈, 按CTRL+C
強制退出會看到以下的輸出:
sigHandle: 2, SIGINT
當然, 直接從進程管理殺死程式就沒辦法收到訊號的.
<signal.h>
中除了signal
函數, 還有一個raise
函數用於產生訊號:
int raise(int sig);
我們在sigHandle
截獲訊號之後如果想重新恢複訊號, 可以使用raise
函數. 但是, 要注意不要導致無窮遞迴signal/raise
調用.
Go語言如何處理CTRL+C
Go語言也有類似的函數signal.Notify
(在os/signal
包中), 可以過濾訊號.
這是signal.Notify
內建的例子:
// Set up channel on which to send signal notifications.// We must use a buffered channel or risk missing the signal// if we're not ready to receive when the signal is sent.c := make(chan os.Signal, 1)signal.Notify(c, os.Interrupt, os.Kill)// Block until a signal is received.s := <-cfmt.Println("Got signal:", s)
signal.Notify
會將使用者關注的訊號轉寄到通道c
, 通道c
不能是阻塞的. 如果通道是緩衝不足的話, 可能會丟失訊號. 如果我們不再次轉寄訊號, 設定為1個緩衝大小就可以了.
signal.Notify
從第二個參數起是可變參數的, 用於指定要過濾的訊號.
如果不指定第二個參數, 則預設是過濾全部的訊號.
訊號的定義一般在syscall
. syscall
包是系統相關的,
不同的作業系統訊號可能有差異. 不過syscall.SIGINT
和syscall.SIGKILL
各個系統是一致的, 分別對應os.Interrupt
和os.Kill
.
下面是Go語言版完整的例子:
package mainimport ( "fmt" "os" "os/signal")func main() { c := make(chan os.Signal, 1) signal.Notify(c, os.Interrupt, os.Kill) s := <-c fmt.Println("Got signal:", s)}
go run signal.go
運行後會進入死迴圈, 按CTRL+C
強制退出會看到以下的輸出:
Got signal: interrupt
當然, 直接從進程管理殺死程式就沒辦法收到訊號的.
如果要恢複訊號, 調用s.Signal()
. 如果要停止訊號的過濾, 調用signal.Stop(c)
.