操作sigset的接口(sigpending,sigprocmask的详细介绍),示例代码(阻塞某信号,修改全部信号的处理方法,阻塞全部信号),介绍9号/19号信号

目录

操作sigset_t的接口

介绍

sigpending

函数原型

返回值

​编辑

sigprocmask

函数原型

 how

set

oldset

示例代码

使特定信号被阻塞 -- 观察pending信号集的变化

代码

运行情况

全部信号被自定义处理

引入

代码

.sh文件

.cpp文件

运行情况

跳过9号信号 

跳过9和19号信号

全部信号被阻塞

引入

代码

运行情况

跳过9号信号

总结 

SIGKILL

SIGSTOP


了解了sigset_t是一个什么样的类型之后,就可以来操作它了

但是,sigset_t禁止对它直接操作,只能通过os提供的接口操作,也就是下面介绍的这些函数:

操作sigset_t的接口

介绍

下面我们详细介绍两个接口: 

sigpending

函数原型

用于获取当前进程的pending信号集

相当于,将os中的数据以set参数的形式,拿给用户

返回值

sigprocmask

函数原型

获取/修改当前进程的阻塞信号集/阻塞屏蔽字

 how

  • 添加信号 -- 相当于mask|set
  • 删除信号 -- 相当于mask~set
  • 替换 -- 相当于mask=set
set

表示要修改的信号集合

oldset
  • 输出型参数,用于获取修改前的信号集(万一会用到呢)
  • 如果不用,一般传NULL

 

示例代码

我们用一些代码来验证某些概念和行为:

使特定信号被阻塞 -- 观察pending信号集的变化

代码
#include <signal.h>
#include <iostream>
#include <cstdlib>
#include <unistd.h>
using namespace std;

void showset(sigset_t *s)
{
    for (int i = 1; i <= 31; ++i)
    {
        if (sigismember(s, i))
        {
            cout << "1";
        }
        else
        {
            cout << "0";
        }
    }
    cout << endl;
}
void func(int signum)
{
    cout << "我收到了" << signum << "号信号" << endl;
}
void test1()
{
    sigset_t s, olds;
    sigset_t pending;
    signal(2, func);
    sigemptyset(&s);
    sigemptyset(&olds);

    sigaddset(&s, 2);                  // 将2号信号添加进去
    sigprocmask(SIG_BLOCK, &s, &olds); // 屏蔽2号信号
    int count = 0;
    while (1)
    {
        ++count;
        sigpending(&pending);
        showset(&pending);
        sleep(1);
        if (count == 10)
        {
            sigprocmask(SIG_UNBLOCK, &s, &olds); // 取消2号信号的屏蔽
        }
    }
}
运行情况

这里我们可以看到pending信号集的变化过程:

  • 从最开始什么信号都没有收到
  • 到收到键盘键入的ctrl c后,第2位bit变成了1
  • 但因为2号信号被阻塞,所以不会被处理
  • 当10s过后,进程解除了信号的阻塞,它就调用了我们的自定义处理函数,并且pending中对应bit位变成了0

 

全部信号被自定义处理

引入
  • 如果全部都用自定义处理方法,并且该函数不包括终止进程功能
  • 那么我们的进程是否就无法被终止了呢?
  • 我们来验证一下:
代码
.sh文件
#!/bin/bash

i=1
id=$(pidof code)

# 发送信号
while [ $i -le 31 ]
do
    kill -$i $id
    echo "kill -$i $id"
    let i++
    sleep 1
done
.cpp文件

我们将所有信号的处理方法,都修改成自定义函数:

void func(int signum)
{
    cout << "我收到了" << signum << "号信号" << endl;
}

void test3()
{
    for (int i = 1; i <= 31; ++i)
    {
        signal(i, func);
    }
    while (1)
    {
        sleep(1);
    }
}
运行情况
  • 当我们用shell脚本给当前进程发送所有信号:
  • 当发到9号信号时,信号终止了
  • 说明9号信号不允许修改方法

跳过9号信号 
#!/bin/bash

i=1
id=$(pidof code)

# 发送信号
while [ $i -le 31 ]
do
    if [ $i -eq 9 ];then
        let i++
        continue
    fi

    kill -$i $id
    echo "kill -$i $id"
    let i++
    sleep 1
done

会发现,19号信号也无法被修改:

跳过9和19号信号
#!/bin/bash

i=1
id=$(pidof code)

# 发送信号
while [ $i -le 31 ]
do
    if [ $i -eq 9 ];then
        let i++
        continue
    fi
    if [ $i -eq 19 ];then
        let i++
        continue
    fi
    
    kill -$i $id
    echo "kill -$i $id"
    let i++
    sleep 1
done

 当我们shell脚本执行完后,进程依然没有退出,

除非我们手动给当前进程发送9号信号 -- SIGKILL:

全部信号被阻塞

引入
  • 我们将所有信号都阻塞,也就是说,进程无法处理任何信号
  • 是否这个进程就无法被终止了呢?
  • 我们来验证一下:
代码
void block_sig(sigset_t* s){
    sigfillset(s); 
    sigprocmask(SIG_SETMASK, s, nullptr); //将所有信号阻塞
}
void test2(){
    sigset_t s,pending;
    sigemptyset(&s);
    block_sig(&s);
    while (1)
    {
        sigpending(&pending);
        showset(&pending);
        sleep(1);
    }
}

运行情况
  • 进程执行后,运行我们的shell脚本,给我们的进程依次发送信号:
  • 会发现,当发送9号信号后,进程被终止了:
  • 说明9号信号无法被阻塞

跳过9号信号
  • 发送19号信号后,该进程被stop:
  • 说明19号信号也无法被阻塞

 

总结 

SIGKILL

是上面例子中提到的9号信号

  • 从运行情况我们可以知道,9号信号无法被阻塞,无法被修改行为
  • 总的来说,它是一种无法被捕获、阻塞或忽略的信号
  • 强制终止进程,不给予进程执行任何清理工作的机会

SIGSTOP

  • 在上面的例子中,他和9号信号一样,都不能被阻塞/被修改行为
  • 19号对应的是SIGSTOP 信号,作用是暂停(停止)一个进程的执行,也是一种无法被捕获、阻塞或忽略的信号
  • SIGSTOP 不会终止进程,而是将其挂起,暂停其执行直到收到 SIGCONT 信号(18号)为止
  • 3
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值