信号是Linux系统提供的另一种进程通信机制。
手册
手册 | 功能简介 |
---|---|
signal(7) | 信号概述 |
signal(2) | 设置信号处理函数 |
kill(2) | 发送信号的函数 |
kill(1) | 发送信号的命令 |
raise(3) | 向当前进程发送信号 |
信号
顾名思义,可以发信号,它不叫数据,也就是说,数据量很少,类似于脉冲。不过“脉冲”的种类很多,在signal(7)中可以看到,信号有很多种,比如常用的ctrl+c
就是向前台进程发送一个SIGINT
信号,SIGKILL
是杀进程的信号。
信号处理函数
每个进程对于每个信号都有一个信号处理函数,当进程收到信号时,信号处理函数会被调用,默认的信号处理函数会杀死当前进程,如果要在某种信号下做一些自定义处理,可以用signal(2)设置自定义的信号处理函数。系统提供了两个现成的信号处理函数,SIG_IGN
是忽略信号,SIG_DFL
是默认信号处理函数。
代码演示
#include <unistd.h>
#include <signal.h>
#include <stdio.h>
#include <sys/types.h>
static int stage = 0;//表示演示阶段,共有3个演示
//自定义信号处理函数
static void sighandler(int sig){
printf("%d receive signal %d\n", getpid(), sig);
stage++;
if (stage > 2){//三个演示完成后结束进程
_exit(0);
}
}
int main(int argc, char **argv)
{
pid_t pid = fork();
if (pid > 0){
//父进程,发送信号
sleep(1);//等子进程设定好信号处理函数
printf("%d send signal %d to %d\n", getpid(), SIGINT, pid);
kill(pid, SIGINT);//向子进程发送一个ctrl+c信号
waitpid(pid,NULL,0);
}
else if (pid == 0){
//子进程
signal(SIGINT, sighandler);//为ctrl+c设定信号处理函数
while (stage < 1);//等待信号处理函数完成
printf("%d send signal %d to %d\n", getpid(), SIGINT, getpid());
raise(SIGINT);//向自己进程发送ctrl+c信号
while (stage < 2);//等待信号处理函数完成
printf("Please use \"kill -2 %d\"\n", getpid());
while (stage < 3);//等待用户用kill命令发送信号
}
return 0;
}
运行与输出
# gcc test.c -o test && ./test &
[1] 82086
82096 send signal 2 to 82097
82097 receive signal 2
82097 send signal 2 to 82097
82097 receive signal 2
Please use "kill -2 82097"
# kill -2 82097
82097 receive signal 2
[1]+ Done gcc test.c -o test && ./test
第一个演示是主进程发送信号给子进程,所以82096是主进程,82097是子进程。信号的值为2,即SIGINT
。
第二个演示是,子进程自己发信号给自己,触发了自己的信号处理函数。
第三个演示是,用户用kill命令主动向子进程发信号,最后子进程也收到了。
信号组可以去了解一下。