您的位置:首页 > 运维架构 > Linux

Linux信号(一)——子进程的异步等待方式

2017-06-16 18:50 337 查看

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){

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


运行结果:

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息