Linux系统信号集

信号的处理方式

①信号忽略
signal(signum, SIGINT)
②信号缺省(执行默认动作)
signal(signum, SIG_DFL)
③信号捕捉(去执行指定的行为)
signal(signum, function)
④信号阻塞

linux系统信号集

什么是信号集?
信号集是一个集合,而每一个成员都是一个信号,通过将信号加入到信号集中,再设置阻塞状态给信号集,那么整个信号集里面的信号都是阻塞状态。
信号阻塞是什么?
进程使用信号集在阻塞某个信号的前提下,收到了这个信号,不会马上响应,而是等到解除阻塞之后,才会响应这个信号。

如果一个进程会收到多个信号,但是进程正在执行其他任务,需要执行完当前任务再去处理这些信号,那么可以使用信号集将收到的所有信号设置为阻塞态,等到解除阻塞,再去执行收到的信号。

信号集处理函数

#include <signal.h>
sigset_t //信号集的数据类型
int sigemptyset(sigset_t *set); //清空信号集
int sigfillset(sigset_t *set); //将Linux下所有的信号加入信号集
int sigaddset(sigset_t *set, int signum); //将signum信号加入信号集
int sigdelset(sigset_t *set, int signum); //将signum信号从信号集里删除
int sigismember(const sigset_t *set, int signum); //判断signum是否在信号集里
参数:
set------>信号集的地址
signum:----->待处理的信号值
返回值:
sigismember(const sigset_t *set, int signum)信号在信号集里返回1,不在信号集里返回0,出错返回-1;
其余的信号集处理函数成功返回0,失败返回-1;

int sigprocmask(int how, const sigset_t *set, sigset_t *oldset);
函数功能:
将信号集设置为阻塞状态 或 解除阻塞状态
参数:
how----->SIG_BLOCK(将信号集设置为阻塞态) / SIG_UNBLOCK(解除信号集的阻塞态)
set----->信号集的地址
oldset----->保留信号集之前的状态的指针,如果不保留之前的状态,就设置为NULL
返回值:
成功返回0,失败返回-1

练习1:练习1:创建一个子进程,父进程将SIGUSR1加入到信号集中,判断信号在不在信号集中,再设置该信号为阻塞状态,该状态持续10s,10s解除阻塞,看看会不会响应信号?子进程在10s之内发送信号SIGUSR1给父进程。

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


void signal_handle(int arg)
{
    printf("parent catch %d, i am handling \n", arg);
}

int main(int argc, char const *argv[])
{
    //捕捉信号
    signal(SIGUSR1, signal_handle);
    
    pid_t id;
    
    id = fork();

    if(id > 0)  //父进程
    {
        printf("i am parent process [%d]\n", getpid());

        sigset_t set;   //信号集
        sigemptyset(&set);  //清空信号集
        sigaddset(&set, SIGUSR1);   //将SIGUSR1信号加入到信号集
        if(sigismember(&set, SIGUSR1) == 1) //判断SIGUSR1是否在信号集中
        {
            printf("yes, SIGUSR1 is member of set\n");
            //将信号集设置为阻塞状态
            sigprocmask(SIG_BLOCK, &set, NULL);
            printf("set is blocked\n");
            sleep(10);  //阻塞10秒
            //将信号集接触阻塞
            printf("set is unblocked\n");
            sigprocmask(SIG_UNBLOCK, &set, NULL);
        }  
        else
            printf("no, SIGUSR1 is not member of set\n");
    }
    else if(0 == id)    //子进程
    {
        sleep(1);
        printf("i am child process[%d]\n", getpid());
        if(0 == kill(getppid(), SIGUSR1))   //向父进程发送SIGUSR1信号
        {
            printf("child send SIGUSR1 to parent\n");
        }
    }

    return 0;
}


在这里插入图片描述

结果分析:在父进程将set信号集设置为阻塞状态后,当父进程收到子进程发送来的SIGUSR1信号
后,将会把信号挂起,直到接触信号集阻塞,才会执行信号响应函数。

练习2:向进程发送相同的几个信号,验证在进程的信号集里,相同的信号将会被舍弃。

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

void signal_handle(int arg)
{
    printf("%d i am running\n", arg);
}

int main(int argc, char const *argv[])
{
    signal(SIGUSR1, signal_handle);

    //定义一个信号集
    sigset_t set;

    //初始化信号集(清空)
    sigemptyset(&set);

    //将信号添加到信号集
    sigaddset(&set, SIGUSR1);

    //判断SIGUSR1是否在信号集中
    if(sigismember(&set, SIGUSR1) == 1)
    {
        printf("SIGUSR1在set信号集中\n");
    }
    else
    {
        printf("SIGUSR1不在set信号集中\n");
    }

    //将信号集设置为阻塞状态    设置的阻塞对象是信号,不是进程
    sigprocmask(SIG_BLOCK, &set, NULL);

    sleep(5);
    //向进程自己发送三次SIGUSR1信号
    raise(SIGUSR1);
    raise(SIGUSR1);
    raise(SIGUSR1);
    //在sleep(5)的期间,收到信号SIGUSR1后,进程将信号挂起来,直到解除阻塞,执行信号响应函数

    //接触信号集阻塞
    sigprocmask(SIG_UNBLOCK, &set, NULL);
    

    return 0;
}

在这里插入图片描述

结果分析:在信号集中,不会存在相同的信号,相同的信号将会被舍弃。

练习3:验证阻塞属性会不会被子进程继承。

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

void signal_handle(int arg) //信号响应函数
{
    printf("[%d] is handling signal of %d\n", getpid(), arg);
}

int main(int argc, char const *argv[])
{   
    pid_t id;

    signal(SIGUSR1, signal_handle);    //信号捕捉函数

    sigset_t set;   //信号集
    sigemptyset(&set);  //清空信号集
    sigaddset(&set, SIGUSR1);   //将SIGUSR1加入到信号集set
    if(1 == sigismember(&set, SIGUSR1)) //判断SIGUSR1是否在信号集set中
        printf("SIGUSR1 is member of set\n");
    else
        printf("SIGUSR1 is not member of set\n");

    sigprocmask(SIG_BLOCK, &set, NULL);    //将信号集里的信号设置为阻塞状态

    id = fork();

    if(id > 0)
    {
        printf("i am parent process[%d]\n", getpid());
        //在父进程里将信号集接触阻塞状态
        sigprocmask(SIG_UNBLOCK, &set, NULL);
        while(1);
    }
    else if(0 == id)
    {
        printf("i am child process[%d]\n", getpid());
        while(1);
    }
    else
    {
        perror("fork");
        exit(1);
    }

    return 0;
}


在这里插入图片描述
在这里插入图片描述

结果分析:子进程继承了父进程的信号集里的阻塞信号,当子进程收到该信号后,不会去执行响应函数,因为该信号被阻塞了;而父进程在接触信号集的阻塞后,可以正常的去执行信号响应函数。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值