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