Linux 信号的阻塞和未决

最近看了一下LInux信号的相关内容,一些博客说的不是很清楚,所以我又整理了一下。

主要不清楚的点在于红色标注的地方,可以参考代码运行一下 测试4 看看。

信号的状态
    到达:表示执行信号处理
    未决:记录信号是否产生
    阻塞:表示是否阻塞某个信号,相当于一个开关
    
    信号在内核中的处理,用两个状态字{阻塞/读写,未决/只读}
    信号 阻塞mask 未决mask 信号处理函数
    1       1               1                      //信号产生了,但是由于阻塞还未处理
    2       0               0                      //信号产生就直接处理
    3       1               0                      //信号还未产生
    ...  ...
    阻塞mask在 task_struct中使用{sigset_t    blocked;}来记录,占据64bit
    为1表示阻塞,为0表示非阻塞
    阻塞mask可以sig...系列函数来设置,通过man sigsetops查看
    
    未决mask:1表示未决(信号已经产生),0表示信号可以抵达(未产生信号)
    
    在接受信号时,内核首先判断信号屏蔽状态字是否阻塞,
        如果该信号被设为阻塞,那么信号未决状态字(pending)相应位置1,
            表示有信号到达但是由于阻塞没有办法处理,处于未决状态;
        如果该信号被设为非阻塞,则直接调用信号处理
            
    在解除信号阻塞时,如果未决状态字为1,那就就处理该信号,并将未决状态置位0

    
    可以利用 int sigpending(sigset_t *set);函数查看有那些信号由于阻塞尚未被处理

#include <unistd.h>  
#include <stdio.h>   
#include <sys/types.h>

//文件 系统调用

#include <sys/stat.h>
#include <fcntl.h>

// 信号
#include <signal.h>

//获取限制
#include <sys/time.h>
#include <sys/resource.h>

// wait调用
#include <sys/wait.h>

// 断言
#include <assert.h>


// 结束状态处理
void handle_exit(int wstatus){
    if(WIFEXITED(wstatus)){
        // 正常结束,结束状态
        printf("normal: %d\n",WEXITSTATUS(wstatus));
    } else {
        if(WIFSIGNALED(wstatus)){
            // 信号状态
            printf("abnormal: signal %d\n",WTERMSIG(wstatus));
        }
    }
}

// alarm 处理
void alarm_handle(int num){
    printf("alarm_handle: %d\n",num);
    alarm(1);
}

void int_handle(int num){
    printf("int_handle: %d\n",num);
}

int main ()   
{   
    //测试 1 wait 的使用
    /*
    int wstatus;
    pid_t pid;
    pid = fork();
    
    assert(pid!=-1);
    if(pid==0){
        // son 
        exit(7);
    } else {
        wait(&wstatus);
        handle_exit(wstatus);
    }
    
    pid = fork();
    assert(pid!=-1);
    if(pid==0){
        // son 
        abort();
    } else {
        waitpid(pid, &wstatus, 0);
        handle_exit(wstatus);
    }
    */
    
    //测试 2 信号的注册 发送信号
    /*
    int wstatus;
    int pid = fork();
    assert(pid!=-1);
    if(pid==0){
        // son 
        execv("./hello.out",NULL);
    } else {
        // father  
        sleep(1); // 睡眠一下,等待子进程完成信号的注册
        kill(pid, SIGINT); //发送信号
        waitpid(pid, &wstatus, 0);
        handle_exit(wstatus);
    }
    */
    
    //测试 3 alarm循环
    /*
    signal(SIGALRM,alarm_handle);
    alarm(1);
    while(1)
        pause();
    */
    
    // 测试4 信号状态
    /*
    sigset_t old;
    sigset_t new;
    sigset_t pending;
    
    // 注册 SIGINT 的处理函数
    signal(SIGINT,int_handle);
    
    // 读取并打印现在的状态字
    sigprocmask(0,NULL,&old);
    sigpending(&pending);
    printf("读取并打印现在的状态字\n");
    printf("block: %lu\n", sigismember(&old,SIGINT) );
    printf("pendi: %lu\n", sigismember(&pending,SIGINT) );

    // 阻塞 SIGINT
    printf("\n阻塞 SIGINT\n");
    sigemptyset(&new);
    sigaddset(&new, SIGINT);
    sigprocmask(SIG_BLOCK,&new,&old);   //阻塞
    sigprocmask(0,NULL,&old);   //读取现在的状态
    sigpending(&pending);
    printf("block: %d\n", sigismember(&old,SIGINT) );
    printf("pendi: %d\n", sigismember(&pending,SIGINT) );
    
    // 给自己发送信号, 由于已经阻塞,不能处理
    printf("\n给自己发送信号, 由于已经阻塞,不能处理\n");
    raise(SIGINT);
    sigprocmask(0,NULL,&old);
    sigpending(&pending);
    printf("block: %d\n", sigismember(&old,SIGINT) );
    printf("pendi: %d\n", sigismember(&pending,SIGINT) );
    sleep(1);   //等待信号处理
    
    // 解除阻塞
    printf("\n解除阻塞\n");
    sigprocmask(SIG_UNBLOCK,&new,&old);
    sigpending(&pending);
    printf("block: %d\n", sigismember(&old,SIGINT));
    printf("pendi: %d\n", sigismember(&pending,SIGINT) );
    
    sleep(1);   //等待信号处理
    */
    return 0;  
}  















猜你喜欢

转载自blog.csdn.net/zhangshuaiisme/article/details/88649167
今日推荐