Linux信号(一)——子进程的异步等待方式
程序员文章站
2022-07-12 10:28:45
...
1.信号
信号(是一种软件中断)是由用户、系统或者进程发送给目标进程的信息,以通知目标进程某个状态的改变或系统异常。
2.信号的产生
(1)前台进程,用户可以通过输入特殊终端字符来给它发送信号。比如Ctrl+C通常给进程发送一个中断信号——2号信号(SIGINT),只能终止前台进程(后台进程一般在运行后面加&,就可以使得进程在后台运行)。
(2)系统异常。比如浮点异常——8号信号(SIGFPE)。
(3)系统状态变化。比如alarm函数定时器到期引起14号信号——SIGALRM信号。
(4)运行kill命令调用kill函数。产生9号信号——SIGKILL(该信号不能被定义或捕捉,该信号用来杀死进程)。
3.信号的分类
列表中,编号为1~31号信号为普通信号,也称为不可靠信号;编号34~64为后来扩充的,被称作可靠
信号(实时信号);不可靠信号和可靠信号二者的区别是前者不支持排队,可能会造成信号丢失,
后者不会。
4.Linux信号处理方式
(1)忽略此信号。大多数信号都可以使用这种方式进行处理,除了9)SIGKILL和19)SIGSTOP。这两种信号不能被忽略的原因:它们是用来终止进程的一种可靠的方法。如果忽略某些由硬件异常所产生的信号(例如非法存储访问或除以0),则进程的行为是未定义的。
(2)执行默认动作(大部分的默认动作就是终止该进程(Term)),还有比如:忽略信号(Ign)、结束进程并生成核心转储文件(Core)、暂停进程(Stop)、以及继续进程(Cont)。
(3)捕捉信号。提供一个自定义的动作。
5.信号相关函数
(1)signal函数
#include<signal.h>
void(*signal (int signo ,void (*func)(int))) (int);
//返回则为以前的信号处理配置,若出错则为SIG_ERR
signo参数是上图的信号名。
func的值为:
如果指定为常数SIG_IGN,代表内核忽略此信号(SIGKILL和SIGSTOP不能忽略) ;
如果指定为常数SIG_DFL,代表接到此信号之后执行系统默认动作
如果指定为函数地址时,我们称捕捉此信号。
(2)kill和raise函数
#include <sys/types.h>
#include <signal.h>
int kill (pid_t pid, int signo);
int raise(int signo);
//两个函数返回:成功则为0,若出错则为-1
kill命令调用kill函数实现,kill函数给一个指定的进程发送指定的信号
raise函数只允许进程向自身发送信号
6.验证子进程退出会给父进程发送信号
测试代码:
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <unistd.h>
#include <signal.h>
#include <error.h>
void catchsignal(int sig)
{
printf("I am a father my pid is:%d , receive signal is %d\n",getpid(),sig);
}
int main()
{
signal(SIGCHLD,catchsignal);
pid_t id=fork();
if(id==0){
//child
int count=0;
while(count<4){
printf("I am a child,my pid is: %d ,my father's pid is: %d \n",getpid(),getppid());
sleep(1);
count++;
}
exit(0);
}
else if(id>0){
//father
waitpid(id,NULL,0);
}
else{
perror("fork error\n");
}
return 0;
}
运行结果:
很明显子进程退出时父进程收到了17号信号——17)SIGCHLD。
7.编写父进程等待子进程的异步版本
异步:父子进程互不干扰(非阻塞式等待),继续执行各自任务。
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <unistd.h>
#include <signal.h>
#include <error.h>
void catchsignal(int sig)
{
printf("I am a father my pid is:%d , receive signal is %d\n",getpid(),sig);
}
int main()
{
signal(SIGCHLD,catchsignal);
pid_t id=fork();
if(id==0){
//child
int count=0;
while(count<4){
printf("I am a child,my pid is: %d ,my father's pid is: %d \n",getpid(),getppid());
sleep(1);
count++;
}
exit(0);
}
else if(id>0){
//father
while(1){
sleep(2);
printf("I am a father,running\n");
}
}
else{
perror("fork error\n");
}
return 0;
}
运行结果:
上一篇: 捕捉信号的总结
下一篇: 双路低频信号发生分析仪(部分)