天天看点

sigwaitinfo

群里问 , 用信号处理函数还需要考虑可重入问题 , 各种中断调用, 有没有简单的方法;

sigwaitinfo(sigset_t * set , siginfo_t * info) ; 

阻塞函数, 用来同步化的解决信号问题; 一旦待检测的 sigset_t * set 中有任一信号发生(pending) 即返回此信号,

由于他检测的是pending信号, 话外之意就是你应该使用sigprocmask 来屏蔽待检测 set 中的信号 

比如你要等待一个SIGINT信号:

sigset_t mask;
    siginfo_t info;
    sigaddset(&mask,SIGINT);
    sigprocmask(SIG_BLOCK, &mask,NULL);
    int signo = sigwaitinfo(&mask,&info);
           

下面是完整的例子:

#include <signal.h>
#include <sys/mman.h>
#include <semaphore.h>
#include <sys/types.h>
#include <sys/wait.h>


//SIGQUIT 用
void handler(int s){
    printf("handler :%d\n" ,s);
}

int main(int argc, char**argv)
{
    signal(SIGQUIT ,handler); // ctrl + \, 此信号没BLOCK
    siginfo_t info;
    sigset_t mask;
    //sigfillset(&mask);
    sigaddset(&mask,SIGRTMIN+1);
    sigaddset(&mask , SIGRTMIN+2);
    sigprocmask(SIG_BLOCK, &mask,NULL); //设置屏蔽

    int pid = fork();
    if(0 == pid){
        //child
        puts("child start");
        kill(getppid(), SIGRTMIN+1); //或用sigqueue
        kill(getppid(),SIGRTMIN+2);
        kill(getppid(), SIGRTMIN+1);
        return 0;
    }
    //parent
    int sig = -1;
    while(1){
        //阻塞等待
        sig = sigwaitinfo(&mask,&info);
        if(sig < 0){
            if(errno == EINTR) {
                
                // 上面 sigquit 将在这里中断
                perror("sigwaitinfo ");
                continue;
            }
            printf("parent error:%s\n" , strerror(errno));
            break;
        }

        //回收子进程
        if(SIGCHLD == sig){
            puts("child is done");
            while(waitpid(-1,0,WNOHANG) > 0);
        }

        printf("sig:%d , from pid:%d , code:%d , signo:%d\n" , sig, info.si_pid,info.si_code,info.si_signo);

        //ctrl+c 就结束了
        if(SIGINT == sig){
            break;
        }
    }



    return 0;
}
           

还有个附带超时功能的 sigtimedwait , 就比sigwaitinfo多一个时间参数, 我就不写了

还有一个相同能的sigwait , 用法类似, 不写了, 特别想睡觉;