目录
一,信号的概念
1.信号是一种在软件层次上对中断机制的模拟,是一种异步通信方式;
2.信号可以直接进行用户空间进程和内核进程之间的交互,内核进程也可以利用信号来通知用户,关于空间进程发生了哪些系统事件;
3.如果一个进程当前并未执行,则该信号就由内核保存起来,直到进程执行或者恢复执行后再传递;如果一个信号被进程设置为阻塞,则信号的传递将会被延迟,直到阻塞被取消才能传递给进程;
二,信号的响应方式(用户处理信号的方式)
1.忽略该信号:不对信号做任何处理,但是有两个信号不能忽略,SIGKILL和SIGSTOP;
2.捕捉该信号:定义信号函数,当信号发生时,执行相应的信号处理函数;
3.执行缺省操作:也就是默认操作,Linux对每种信号都规定了默认操作。
三,信号种类
信号 | 值 | 性质 | 默认处理方式 |
SIGKILL | 9 | 当产生这个信号后,当前进程就会退出,不能被缺省或捕捉 | 退出进程 |
SIGSTOP | 19 | 当产生这个信号后,当前进程会停止,不能被缺省或捕捉 | 停止进程 |
SIGINT | 2 | 键盘键入Ctrl+c时产生的信号 | 退出进程 |
SIGQUIT | 3 | 键盘键入Ctrl+\时产生的信号 | 退出进程 |
SIGTSTP | 20 | 键盘键入Ctrl+z时产生的信号 | 停止进程 |
SIGCONT | 18 | 当产生当前信号后,当前停止的进程会恢复运行 | 停止的进程恢复运行 |
SIGALRM | 14 | 当alarm函数设置的时间到达时,会产生当前信号 | 退出进程 |
SIGPIPE | 13 | 当管道破裂时,会产生当前信号 | 退出进程 |
SIGABRT | 6 | 当调用abort函数时会产生当前信号 | 退出进程 |
SIGCHLD | 17 | 当使用fork创建一个子进程时,如果子进程状态改变或退出,则会产生当前信号 | 缺省 |
SIGUSR1 | 10 | 用户自定义的信号,不会自动产生,只能使用kill函数或者命令给指定的进程发送当前信号 | 缺省 |
SIGUSR2 | 12 | 用户自定义信号,不会自动产生,只能使用kill函数或者命令给指定的进程发送当前信号 | 缺省 |
四,信号函数接口
1.int kill(pid_t pid,int sig);
功能:给指定进程发送信号;
参数:pid->指定进程的进程号;sig->要发送的信号;
返回值:成功为0,失败为-1;
2.int raise(int sig);
功能:进程向自己发送信号;
参数:sig->信号;
返回值:成功为0,失败为-1;
3.unsigned int alarm(unsigned int seconds)
功能:在进程中设置一个定时器;
参数:seconds->定时时间,单位为秒;
返回值:如果该alarm函数是进程中第一次调用,则返回0,如果不是第一次调用,则返回上一次调用alarm函数剩余的时间;
注意:一个进程中,如果多次调用alarm函数,进程中的闹钟时间将会被最后一次调用的alarm函数所设定的时间确定。
4.int pause(void);
功能:用于将调用该函数的进程挂起,直到接收到信号为止;
5.typedef void (*sighandler_t)(int);
sighandler_t signal(int signum,sighandler_t handler);
功能:接收信号,并进行相应操作;
参数:signum->要处理的信号;
handler->信号的处理方式:SIG_IGN忽略信号;SIG_DFL默认操作和handler用户自定义的信号处理函数;
参数:成功则执行设置的信号处理方式,失败则返回-1;
代码演示:实现司机和售票员问题;
#include <stdio.h>
#include <unistd.h>
#include <signal.h>
#include <sys/wait.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <stdlib.h>
pid_t pid; //两个信号处理函数和main函数都要使用pid,所以定义为全局变量;
//司机信号处理函数
void hand_bus(int sig)
{
if (sig == SIGUSR1)
{
printf(" let's gogogo!\n");
}
if (sig == SIGUSR2)
{
printf(" stop the bus\n");
}
if (sig == SIGTSTP)
{
//给指定进程(子进程乘务员)发送信号
kill(pid, SIGUSR1);
wait(NULL);
exit(0);
}
}
//乘务员信号处理函数
void hand_staff(int sig)
{
if (sig == SIGUSR1)
{
printf(" please get off the bus\n");
exit(0);
}
if (sig == SIGINT)
{
kill(getppid(), SIGUSR1);
}
if (sig == SIGQUIT)
{
//给指定进程(父进程司机)发送信号
kill(getppid(), SIGUSR2);
}
}
int main(int argc, char const *argv[])
{
if ((pid = fork()) < 0)
{
perror("fork err");
return -1;
}
else if (pid == 0) //staff
{
//接收乘务员要处理的信息,执行乘务员信号处理函数
signal(SIGINT, hand_staff);
signal(SIGQUIT, hand_staff);
signal(SIGUSR1, hand_staff);
//忽略其他信号
signal(SIGUSR2,SIG_IGN);
signal(SIGTSTP,SIG_IGN);
}
else //bus
{
//接收司机要处理的信息,执行乘务员信号处理函数
signal(SIGTSTP, hand_bus);
signal(SIGUSR1, hand_bus);
signal(SIGUSR2, hand_bus);
//忽略其他信号
signal(SIGINT,SIG_IGN);
signal(SIGQUIT,SIG_IGN);
}
pause();
return 0;
}
执行结果为:
如果本文中存在概念错误或代码错误的情况,请批评指正。