zoukankan      html  css  js  c++  java
  • 第8章 信号(5)_信号集和信号屏蔽

    3.5 信号集和信号屏蔽

    (1)信号集函数:信号集为一个或多个信号的集合,主要用在信号屏蔽函数中

    (2)主要的信号集函数

    头文件

    #include <signal.h>

    函数

    ①int sigemptyset(sigset_t* set);// set为信号集,将信号集清空,对应将所有信号屏蔽字置0.

    ②int sigfillset(sigset* set); //将所有信号加入到信号集中,对应将所有信号的屏蔽字置1.

    ③int sigaddset(sigset* set, int signo); //将某个信号加入到信号集中,对应将的信号屏蔽字某位置1.

    ④int sigdelset(sigset* set, int signo); //将某个信号从信号集中删除,对应将的信号屏蔽字某位置0.

    ⑤int sigismember(const sigset_t* set, int signo);//测试信号集中是否包含有某个信号,对应判断信号屏蔽字某位是否置1。真返回1,假返回0,出错返回-1。

     

    函数

    int sigprocmask(int how, const sigset_t* set, sigset_t* oldset);

    功能

    利用set去覆盖内核中的信号屏蔽字,oldset存放原有的信号屏蔽字

    返回值

    成功返回0,出错返回-1.

    参数

    【参数how】:

    ①SIG_BLOCK:利用set中的信号设置信号屏蔽字(设置某些位的置为1)

    相当于mask |= oldest;

    ②SIG_UNBLOCK:利用set中的信号不设置信号屏蔽字(取消某些位置为0)相当于mask &= ~oldset(先取反,再按位与)

    ③SIG_SETMASK:利用set信号去替换内核信号屏蔽字。相当于mask = oldest.

    备注

    (1)进程可以暂时屏蔽信号,使得进程在执行过程中发生的相应信号可以暂时被屏蔽,等待进程解除信号屏蔽后再由内核或驱动将该信号投递给进程

    (2)信号屏蔽可屏蔽程序执行过程中的中断

    函数

    int sigpending(sigset_t* set);

    功能

    获取信号未决字的内容

    返回值

    成功返回0,出错返回-1。

    【编程实验】查看进程的信号屏蔽字

    //signal_mask.c

    #include <signal.h>
    #include <stdio.h>
    #include <stdlib.h>
    
    void out_set(const sigset_t* set)
    {
        int i = 1; //信号是从1开始的
        int bFind = 0;
        for(; i<31; i++){
            //判断信号屏蔽字的某些位置是否置1
            if(sigismember(set, i)){
                bFind |= 1;
                printf("%d ", i); //查看每个信号
            }
        }
    
        if (bFind) 
            printf("
    ");
    }
    
    void sig_handler(int signo)
    {
        printf("begin process the %d
    ", signo);
    
        //获得正在处理信号时内核中的信号屏蔽字的内容
        sigset_t oset; //放置内核信号屏蔽字的内容
        //清空信号集oset
        sigemptyset(&oset);
        if(sigprocmask(SIG_BLOCK, NULL, &oset) < 0){
            perror("sigprocmask error");
        }
        out_set(&oset); //输出信号屏蔽字的内容
        
        printf("finish process the %d
    ", signo);
    }
    
    int main(void)
    {
        if(signal(SIGUSR1, sig_handler) == SIG_ERR){
            perror("signal sigusr1 error");
        }
    
        if(signal(SIGUSR2, sig_handler) == SIG_ERR){
            perror("signal sigusr2 error");
        }
    
        sigset_t oset; //放置内核信号屏蔽字的内容
        printf("before signal occured mask:
    ");
     
        //清空信号集oset
        sigemptyset(&oset);
        //在信号发生前,获得信号屏蔽字的内容
        if(sigprocmask(SIG_BLOCK, NULL, &oset) < 0){
            perror("sigprocmask error");
        }
        out_set(&oset); //输出信号屏蔽字的内容
    
        printf("process %d wait signal...
    ", getpid()); 
        pause();//进程暂停等待信号
       
        printf("after signal occured mask:
    ");
        sigemptyset(&oset);
        //在信号发生后,获得信号屏蔽字的内容
        if(sigprocmask(SIG_BLOCK, NULL, &oset) < 0){
            perror("sigprocmask error");
        }
        out_set(&oset);
    
        return 0;
    }
    /*输出结果:
     [root@localhost]# bin/signal_mask     
     before signal occured mask: //mask为空
     process 2053 wait signal...
     begin process the 12
     12                          //mask为SIGUSR2
     finish process the 12
     after signal occured mask:  //mask为空
     [root@localhost]# bin/signal_mask
     before signal occured mask: //mask为空
     process 2054 wait signal...
     begin process the 10
     10                          //mask为SIGUSR1
     finish process the 10
     after signal occured mask:  //mask为空
     */

    (3)信号屏蔽设置

      ①信号在处理过程中是被屏蔽的(被置1),处理完毕解除屏蔽(置0)。可在函数可重入性中利用信号屏蔽技术。

      ②内核中的task_struct中包含两个32位字(记录相关的信号信息),分别是信号屏蔽字blocked和信号未决字pending。其中:

        blocked共有31位信号,0号没有意义,每一位代表一个信号,初始为0。若为0,则该位上发生信号会被立即处理若为1(设置1则信号被屏蔽,设置0则信号不屏蔽),则在该位上发生信号不会被处理,会延迟处理

        pending初始为0,若blocked中某一位为1,但以发生了同样的信号,则在pending同样的位置会被置为1,以便让进程知道该信号又发生过而进行延迟处理

      ③若干个信号一起设置为0或1称为信号集

      ④子进程继承父进程的信号屏蔽字,而不继承信号未决字

    【编程实验】利用信号屏蔽来防止函数的重入问题

    //signal_reentry2.c

    #include <unistd.h>
    #include <signal.h>
    #include <stdio.h>
    #include <stdlib.h>
    #include <malloc.h>
    
    int  g_v[10]; //全局数组
    int* h_v;     //堆数组
    
    void set(int val)
    {
        int a_v[10]; //局部数组
    
        int i = 0;
        for(; i<10; i++){
            a_v[i] = val;
            g_v[i] = val;
            h_v[i] = val;
    
            sleep(1);
        }
    
        printf("g_v:");
        for(i=0; i<10; i++){
            if(i != 0)
                printf(",%d", g_v[i]);
            else
                printf("%d", g_v[i]);
        }
        printf("
    ");
        
        printf("h_v:");
        for(i=0; i<10; i++){
            if(i != 0)
                printf(",%d", h_v[i]);
            else
                printf("%d", h_v[i]);
        }
        printf("
    ");
    
        printf("a_v:");
        for(i=0; i<10; i++){
            if(i != 0)
                printf(",%d", a_v[i]);
            else
                printf("%d", a_v[i]);
        }
        printf("
    ");
    }
    
    //信号处理函数
    void sig_handler(int signo)
    {
        if(signo == SIGTSTP){
            printf("SIGTSTP occured
    ");
            set(20); //信号处理函数内部再次调用set,以验证函数的
                     //可重入性。注意,传入20
            printf("end SIGTSTP
    ");
        }
    }
    
    int main(void)
    {
        if(signal(SIGTSTP, sig_handler) == SIG_ERR){
            perror("signal sigtstp error");
        }
    
        h_v = (int*)calloc(10, sizeof(int));
        
        printf("begin running main
    ");
       
        //屏蔽信号(1-31)
        sigset_t sigset;
        sigfillset(&sigset); //屏蔽所有信号
        if(sigprocmask(SIG_SETMASK, &sigset, NULL) < 0){
            perror("sigprocmask error");
        }
    
        set(10);  //传入10,由于set之前屏蔽了所有信号,所以这时
                  //即使按ctrl-z,这个信号也不会马上被捕获,这意
                  //味着,执行流没转到信号处理函数,而是正常在main
                  //中执行。
    
        //解除信号屏蔽(如果在屏蔽期间发生信号,会在解释屏蔽之后被发送出去)
        if(sigprocmask(SIG_UNBLOCK, &sigset, NULL) < 0){
            perror("sigprocmask error");
        }
    
        printf("end running main
    ");
    
        free(h_v);
    }
    /*输出结果:
     [root@localhost]# bin/signal_reentry2
     begin running main   //正常执行流,不产生信号
     g_v:10,10,10,10,10,10,10,10,10,10
     h_v:10,10,10,10,10,10,10,10,10,10
     a_v:10,10,10,10,10,10,10,10,10,10
     end running main
     [root@localhost]# bin/signal_reentry2
     begin running main     //运行2-3秒后,按ctrl-z。注意信号并没有
     ^Zg_v:10,10,10,10,10,10,10,10,10,10  //马上被捕获,而是正常执行main函数
     h_v:10,10,10,10,10,10,10,10,10,10
     a_v:10,10,10,10,10,10,10,10,10,10
     SIGTSTP occured                      //解除屏蔽,信号才被发送过来,从而
     g_v:20,20,20,20,20,20,20,20,20,20    //防止的set函数的重入
     h_v:20,20,20,20,20,20,20,20,20,20
     a_v:20,20,20,20,20,20,20,20,20,20
     end SIGTSTP
     end running main
     */

    【编程实验】连续发送同一信号时的信号未决字内容变化

    //signal_pending.c

    #include <stdio.h>
    #include <stdlib.h>
    #include <signal.h>
    
    void out_set(const sigset_t* set)
    {
        int i = 1;
        for(; i<=31; i++){
            if(sigismember(set, i)){
                printf("%d, ", i); //将被屏蔽的信号输出
            }
        }
        printf("
    ");
    }
    
    void sig_handler(int signo)
    {
        printf("begin the signal handler
    ");
        
        int i = 0;
        sigset_t set;
        for(; i<10; i++){       
            printf("(%d)", i + 1);
            
            sigemptyset(&set);
            if(sigpending(&set) < 0){
                perror("sigpending error");
            }else{
                printf("pending signal: ");
                out_set(&set);
            }
    
            sleep(1);
        }
    
        printf("end the signal handler
    ");
    }
    
    int main(void)
    {
        if(signal(SIGTSTP, sig_handler) == SIG_ERR){
            perror("signal sigtstp error");
        }
        
        printf("process %d wait signal...
    ", getpid());
        pause(); //进程暂停等待信号
        printf("process finished.
    ");
    
        return 0;
    }
    /*输出结果:
    [root@localhost]# bin/signal_pending                             
    process 1535 wait signal...
    ^Zbegin the signal handler  //发送ctrl-z,被唤醒,开始执行信号处理函数
    (1)pending signal:          //开始处理信号函数时,信号未决字被清零
    (2)pending signal: 
    (3)pending signal: 
    ^Z^Z^Z^Z(4)pending signal: 20, //连续发送4个ctrl-z信号,由于处理信号过程
    (5)pending signal: 20,         //中,同一类型的信号被屏蔽。此时再发送的
    (6)pending signal: 20,         //同类型信号会被记录在pending中,以便告知
    (7)pending signal: 20,         //系统,又有一个同类型的信号等待处理
    (8)pending signal: 20, 
    (9)pending signal: 20, 
    (10)pending signal: 20, 
    end the signal handler
    begin the signal handler       //处理完第1个信号,开始处理后来未决的信号
    (1)pending signal:             //由于是同类型的,被延迟到第1个信号处理完
    (2)pending signal:             //毕才开始。
    (3)pending signal: 
    (4)pending signal: 
    (5)pending signal: 
    (6)pending signal: 
    (7)pending signal: 
    (8)pending signal: 
    (9)pending signal: 
    (10)pending signal: 
    end the signal handler          //未决信号被处理完毕,同类型只再处理一次
    process finished.
     */
  • 相关阅读:
    VUE权限列表控制
    VUE-element-UI修改内置样式
    微信开发-url地址传值踩坑
    git 上传命令
    微信开发-缩略图插件
    axios拦截器
    设置contentType
    JSON.parse 函数应用 (复制备忘)
    angularjs开发遇到的坑
    http 请求头
  • 原文地址:https://www.cnblogs.com/5iedu/p/6405193.html
Copyright © 2011-2022 走看看