欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

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为后来扩充的,被称作可靠
信号(实时信号);不可靠信号和可靠信号二者的区别是前者不支持排队,可能会造成信号丢失,
后者不会。

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

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

运行结果:

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

很明显子进程退出时父进程收到了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;
}

运行结果:
Linux信号(一)——子进程的异步等待方式