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

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

运行结果:






  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值