Linux进程间通信--信号
signal
一、初步理解信号
为了理解信号 ,先从我们最熟悉的场景说起:
1.用户输入命令,在Shell下启动一个前台进程。
2.用户按下Ctrl-C,这个键盘输入产生一个硬件中断。
3.如果CPU当前正在执行这个进程的代码,则该进程的用户空间代码暂停执行,CPU从用户态切换到内核态处理硬件断。
4. 终端驱动程序将Ctrl-C解释成一个SIGINT信号,记在该进程的PCB中(也可以说发送了一个SIGINT信号给该进程)。
5. 当某个时刻要从内核返回到该进程的用户空间代码继续执行之前,首先处理PCB中记录的信号,发现有一个SIGINT信号待处理,而这个信号的默认处理动作是终止进程,所以直接终止进程而不再返回它的用户空间代码执行。
注意,Ctrl-C产生的信号只能发给前台进程。一个命令 后面加个&可以放到后台运行,这样 Shell不必等待进程结束就可以接受新的命令,启动新的进程。Shell可以同时运行一个前台进 程和任意多个后台进程,只有前台进程才能接到Ctrl-C这种控制键产生的信号。前台进程 在运行过程中用户随时可能按下Ctrl-C而产生一个信号,也就是说该进程的用户空间代码执行到任何地方都有可能收到SIGINT信号而终止,所以信号相对于进程的控制流程来说是异步(Asynchronous)的
二、用kill -l命令可以察看系统定义的信号列表:
每个信号都有一个编号和一个宏定义名称,这些宏定义可以在signal.h中找到,例如其中有 定 义#define SIGINT 2。编号34以上的是实时信号,只讨论编号34以下的信号,不讨论实时信号。这些信号各自在什么条件下产生,默认的处理动作是什么,在signal(7)中都有:
man 7 signal
各类信号的说明都有。
三、信号的产生或者发送
#include <sys/types.h> #include <signal.h> int kill(pid_t pid, int sig);
#include <unistd.h> unsigned int alarm(unsigned int seconds);
#include <unistd.h> #include <sys/types.h> #include <stdlib.h> #include <stdio.h> #include <signal.h> static int alarm_fired = 0; void ouch(int sig) { alarm_fired = 1; } int main() { pid_t pid; pid = fork(); switch(pid) { case -1: perror("fork failed\n"); exit(1); case 0: //子进程 sleep(5); //向父进程发送信号 kill(getppid(), SIGALRM); exit(0); default:; } //设置处理函数 signal(SIGALRM, ouch); while(!alarm_fired) { printf("Hello World!\n"); sleep(1); } if(alarm_fired) printf("\nI got a signal %d\n", SIGALRM); exit(0); }
#include <unistd.h> #include <sys/types.h> #include <stdlib.h> #include <stdio.h> #include <signal.h> static int alarm_fired = 0; void ouch(int sig) { alarm_fired = 1; } int main() { //关联信号处理函数 signal(SIGALRM, ouch); //调用alarm函数,5秒后发送信号SIGALRM alarm(5); //挂起进程 pause(); //接收到信号后,恢复正常执行 if(alarm_fired == 1) printf("Receive a signal %d\n", SIGALRM); exit(0); }
#include <signal.h> void (*signal(int sig, void (*func)(int)))(int);
2.sigaction函数
#include <signal.h> int sigaction(int sig, const struct sigaction *act, struct sigaction *oact);
#include <unistd.h> #include <stdio.h> #include <signal.h> void ouch(int sig) { printf("\nOUCH! - I got signal %d\n", sig); } int main() { struct sigaction act; act.sa_handler = ouch; //创建空的信号屏蔽字,即不屏蔽任何信息 sigemptyset(&act.sa_mask); //使sigaction函数重置为默认行为 act.sa_flags = SA_RESETHAND; sigaction(SIGINT, &act, 0); while(1) { printf("Hello World!\n"); sleep(1); } return 0; }