信号

man 7 signal

 (默认处理动作)

 

杀死父进程:

 

由父进程杀死3号子进程:

raise 函数,给本进程传递信号

abort 函数

 setitimer 函数

 

 (实现alarm)

(第一次5s发SIGALRM,之后每隔3s发一次。signal()函数用于捕捉信号)

实现alarm

信号集处理函数:

 

 

 

 

信号捕捉特性

  1. 进程正常运行时,默认PCB中有一个信号屏蔽字,假定为☆,它决定了进程自动屏蔽哪些信号。当注册了某个信号捕捉函数,捕捉到该信号以后,要调用该函数。而该函数有可能执行很长时间,在这期间所屏蔽的信号不由☆来指定。而是用sa_mask来指定。调用完信号处理函数,再恢复为☆。
  2. XXX信号捕捉函数执行期间,XXX信号自动被屏蔽。
  3. 阻塞的常规信号不支持排队,产生多次只记录一次。(后32个实时信号支持排队)

 

 

 

(在捕捉函数执行期间,屏蔽SIGINT [ctrl+c] 和 SIGQUIT [ctrl+])

利用SIGCHLD信号捕捉回收子进程:

 

如果在sigaction注册之前子进程都已结束,则catch不到SIGCHLD.可以先把SIGCHLD block掉,sigaction注册后恢复。

#include <stdio.h>
#include <unistd.h>
#include <sys/wait.h>
#include <signal.h>

void catch_sig(int num){
    pid_t wpid;
    while((wpid=waitpid(-1,NULL,WNOHANG))>0){
        printf("wait child %d ok
", wpid);
    }
}

int main()
{
    int i=0;
    sigset_t myset,oldset;
    sigemptyset(&myset);
    sigaddset(&myset,SIGCHLD);
    sigprocmask(SIG_BLOCK,&myset,&oldset);

    pid_t pid;
    for(i=0;i<10;i++){
        pid=fork();
        if(pid==0){
            break;
        }
    }
    if(i==10){
        sleep(5);
        struct sigaction act;
        act.sa_flags=0;
        sigemptyset(&act.sa_mask);
        act.sa_handler=catch_sig;
        sigaction(SIGCHLD,&act,NULL);
        sigprocmask(SIG_SETMASK,&oldset,NULL);
        while(1){
            sleep(1);
        }
    }else {
        printf("I am the %d child, pid=%d
", i, getpid());
        //sleep(i);
    }
    return 0;
}

利用信号实现父子进程相互报数:

#include <stdio.h>
#include <unistd.h>
#include <signal.h>

int flag=0;
int count;

void cat_son(int num){
   sleep(1); printf(
"%d ", count); count+=2; flag=1; } void cat_father(int num){
  sleep(1); printf(
"%d ", count); count+=2; flag=1; } int main() { pid_t pid=fork(); if(pid==0){ count=1; pid_t ppid=getppid(); signal(SIGUSR1,cat_son); while(1){ if(flag==1){ kill(ppid,SIGUSR2); flag=0; } } }else{ sleep(1); count=2; signal(SIGUSR2,cat_father); kill(pid,SIGUSR1); while(1){ if(flag==1){ kill(pid,SIGUSR1); flag=0; } } } return 0; }

若catch中没有sleep,会卡死。子进程报完树后执行完kill(ppid,SIGUSR2),父进程开始报数,然后发送SIGUSR1给子进程,子进程报数,flag置为1,然后从kill(ppid,SIGUSR2)之后执行指令,flag=0,不会给父进程发送信号了。

另一种方法:

#include <stdio.h>
#include <unistd.h>
#include <signal.h>

//int flag=0;
int count;
pid_t pid;

void cat_son(int num){
    //sleep(1);
    printf("%d
", count);
    count+=2;
    //flag=1;
    kill(getppid(),SIGUSR2);
}

void cat_father(int num){
    //sleep(1);
    printf("%d
", count);
    count+=2;
    //flag=1;
    kill(pid,SIGUSR1);
}

int main()
{
    pid=fork();
    if(pid==0){
        count=1;
        pid_t ppid=getppid();
        signal(SIGUSR1,cat_son);
        while(1){
            //if(flag==1){
              //  kill(ppid,SIGUSR2);
               // flag=0;
            //}
        }
    }else{
        sleep(1);
        count=2;
        signal(SIGUSR2,cat_father);
        kill(pid,SIGUSR1);
        while(1){
            //if(flag==1){
               // kill(pid,SIGUSR1);
                //flag=0;
            //}
        }
    }

    return 0;
}
原文地址:https://www.cnblogs.com/FEIIEF/p/12500462.html