如果是命令行程序需要退出, CTRL+C是最直接的方法.
C语言如何处理CTRL+C
CTRL+C会向命令行进程发送中断信号, 在C语言的中的signal函数可以注册信号的处理函数.
signal函数的签名如下:
void (*signal(int sig, void (*func)(int)))(int);
比如, 我们要处理CTRL+C对应的SIGINT信号:
#include
#include
#include
void sigHandle(int sig) {
switch(sig) {
case SIGINT:
printf(“sigHandle: %d, SIGINTn”, sig);
break;
default:
printf(“sigHandle: %d, OTHERn”, sig);
break;
}
exit(1);
}
int main() {
signal(SIGINT, sigHandle);
for(;;) {}
return 0;
}
编译并运行程序后会进入死循环, 按CTRL+C强制退出会看到以下的输出:
sigHandle: 2, SIGINT
当然, 直接从进程管理杀死程序就没办法收到信号的.
中除了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 :=
fmt.Println(“Got signal:”, s)
signal.Notify会将用户关注的信号转发到信道c, 信道c不能是阻塞的. 如果信道是缓冲不足的话, 可能会丢失信号. 如果我们不再次转发信号, 设置为1个缓冲大小就可以了.
signal.Notify从第二个参数起是可变参数的, 用于指定要过滤的信号.
如果不指定第二个参数, 则默认是过滤全部的信号.
信号的定义一般在syscall. syscall包是系统相关的,
不同的操作系统信号可能有差异. 不过syscall.SIGINT和syscall.SIGKILL各个系统是一致的, 分别对应os.Interrupt和os.Kill.
下面是Go语言版完整的例子:
package main
import (
“fmt”
“os”
“os/signal”
)
func main() {
c := make(chan os.Signal, 1)
signal.Notify(c, os.Interrupt, os.Kill)
s :=
fmt.Println(“Got signal:”, s)
}
go run signal.go运行后会进入死循环, 按CTRL+C强制退出会看到以下的输出:
Got signal: interrupt
当然, 直接从进程管理杀死程序就没办法收到信号的.
如果要恢复信号, 调用s.Signal(). 如果要停止信号的过滤, 调用signal.Stop(c).