Linux信号之信号的保存

这篇具有很好参考价值的文章主要介绍了Linux信号之信号的保存。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

(。・∀・)ノ゙嗨!你好这里是ky233的主页:这里是ky233的主页,欢迎光临~https://blog.csdn.net/ky233?type=blog

点个关注不迷路⌯'▾'⌯

目录

一、阻塞信号

1.信号递达、未决、阻塞

 2.内核表示图

3.sigset_t

4.sigpending

5.sigprocmask

二、验证问题

1.问题一

2.问题二

3.问题三


一、阻塞信号

1.信号递达、未决、阻塞

  • 实际执行信号的处理动作称为信号递达(Delivery)。

  • 信号从产生到递达之间的状态,称为信号未决(Pending)。
  • 进程可以选择阻塞 (Block )某个信号。
  • 被阻塞的信号产生时将保持在未决状态,直到进程解除对此信号的阻塞,才执行递达的动作。
  • 注意,阻塞和忽略是不同的,只要信号被阻塞就不会递达,而忽略是在递达之后可选的一种处理动作。

 2.内核表示图

Linux信号之信号的保存,服务器,运维

在内核中其实一共有两个位图结构,第二个就是我们的pending位图,也就是OS修改的位图结构,第三个则是代表的信号,是一个函数指针数组,里边存放的是所对应的函数地址

而在handler里面会先判断是否是等0还是1,0则执行默认的动作,1则直接忽略的动作,都不是才会执行我们自己写的动作!

第一个block则代表的是我们的阻塞位图,OS先把对应的信号写入pending里,然后回来查看,block里面是否阻塞,如果阻塞则不进行调用,等到不阻塞时候才回去handler里进行下一步操作!

3.sigset_t

这是一个位图结构,但是不允许用户自己进行位操作,所以OS给我们提供了对应的操作方法

用户可以直接使用该类型,和用内置类型以及自定义类型是没有任何差别的 

每个信号只有一个bit的未决标志,非0即1,不记录该信号产生了多少次,阻塞标志也是这样表示的。 因此,未决和阻塞标志可以用相同的数据类型sigset_t来存储,sigset_t称为信号集,这个类型可以表示每个信号 的“有效”或“无效”状态,在阻塞信号集中“有效”和“无效”的含义是该信号是否被阻塞,而在未决信号集中“有 效”和“无效”的含义是该信号是否处于未决状态。

总的来说就是用来表示block和pending的

int sigemptyset(sigset_t *set);
int sigfillset(sigset_t *set);
int sigaddset (sigset_t *set, int signo);
int sigdelset(sigset_t *set, int signo);
int sigismember(const sigset_t *set, int signo); 

上面就是OS所提供的五个可以对位图本身修改的接口

  1. 函数sigemptyset初始化set所指向的信号集,使其中所有信号的对应bit清零,表示该信号集不包含 任何有 效信号。
  2. 函数sigfillset初始化set所指向的信号集,使其中所有信号的对应bit置位,表示 该信号集的有效信号包括系 统支持的所有信号。
  3. 注意,在使用sigset_ t类型的变量之前,一定要调 用sigemptyset或sigfillset做初始化,使信号集处于确定的 状态。初始化sigset_t变量之后就可以在调用sigaddset和sigdelset在该信号集中添加或删除某种有效信号
  4. sigismember:最后一个是判定一个信号时候再该信号集之中 

4.sigpending

int sigpending(sigset_t *set)

通过该函数可以获取当前调用进程的pending信号集,也就是把操作系统内核中的数据拿给用户

  • 返回值:成功为0,失败为-1

5.sigprocmask

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

检查并更改我们的阻塞信号集

  • 参数一:设定特定的操作
  • 参数二:设定特定的位图
  • 参数三:输出型参数,返回老的信号屏蔽图(阻塞位图block),如果需要的话
  • 返回值:若成功则为0,若出错则为-1

how:

  • SIG_BLOCK:set包含了我们希望添加到当前信号屏蔽字的信号,相当于mask=mask|set
  • SIG_UNBLOCK:set包含了我们希望从当前信号屏蔽字中解除阻塞的信号,相当于mask=mask&~set
  • SIG_SETMASK:设置当前信号屏蔽字为set所指向的值,相当于mask=set

二、验证问题

1.问题一

如果我们对所有的信号都进行了自定义不做,我们是不是就写了一个不会被一场或者用户杀掉的进程?

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

void catchSig(int signum)
{
    cout << "获得了一个信号:" << signum << endl;
}

int main()
{
    for (int i = 1; i <= 31; i++)
    {
        signal(i, catchSig);
    }
    while (1)
    {
        sleep(1);
    }
    return 0;
}

Linux信号之信号的保存,服务器,运维

 虽然我们看到的好像就是这样,可其实并不是,OS设计者也考虑过,我们的9号信号(SIGKILL)是不可以被捕捉的!Linux信号之信号的保存,服务器,运维

2.问题二

如果我们将二号信号阻塞,并且不断地获取并打印当前进程的pending信号,如果我们突然发送一个二号信号,我们应该肉眼看到pending信号集中,有一个比特位从0变为1

static void shouPending(sigset_t &pending)
{
    for (int sig = 1; sig <= 31; sig++)
    {
        if (sigismember(&pending, sig))
        {
            cout << "1";
        }
        else
        {
            cout << "0";
        }
    }
    cout << endl;
}

int main()
{
    // 定义信号集
    sigset_t bset, obset;
    sigset_t pending;
    // 初始化
    sigemptyset(&bset);
    sigemptyset(&obset);
    sigemptyset(&pending);
    // 添加要进行屏蔽的信号
    sigaddset(&bset, 2);
    // 设置set到内核中
    int n = sigprocmask(SIG_BLOCK, &bset, &obset);
    assert(n == 0);
    cout << "2号信号以阻塞" << endl;
    (void)n;
    // 重复打印当前的pending信号集
    while (1)
    {
        // 获取当前进程的pending信号集
        sigpending(&pending);
        // 显示pending中的没有被递达的信号
        shouPending(pending);
        sleep(1);

    }
    return 0;
}

Linux信号之信号的保存,服务器,运维

首先我们看到当前进程的pending位图都是0,这是因为虽然我们阻塞了,但是不代表这个进程收到了2号信号,当我们发完之后,确实如我们所说,有一个比特位由0变1了

Linux信号之信号的保存,服务器,运维 可是如果我们要解除2号信号的阻塞呢?那我们的pending信号集就应该从1变成0!

#include <iostream>
#include <signal.h>
#include <unistd.h>
#include <assert.h>
using namespace std;

static void shouPending(sigset_t &pending)
{
    for (int sig = 1; sig <= 31; sig++)
    {
        if (sigismember(&pending, sig))
        {
            cout << "1";
        }
        else
        {
            cout << "0";
        }
    }
    cout << endl;
}

int main()
{
    // 定义信号集
    sigset_t bset, obset;
    sigset_t pending;
    // 初始化
    sigemptyset(&bset);
    sigemptyset(&obset);
    sigemptyset(&pending);
    // 添加要进行屏蔽的信号
    sigaddset(&bset, 2);
    // 设置set到内核中
    int n = sigprocmask(SIG_BLOCK, &bset, &obset);
    assert(n == 0);
    cout << "2号信号以阻塞" << endl;
    (void)n;
    // 重复打印当前的pending信号集
    int count = 0;
    while (1)
    {
        // 获取当前进程的pending信号集
        sigpending(&pending);
        // 显示pending中的没有被递达的信号
        shouPending(pending);
        sleep(2);
        count++;
        if (count == 10)
        {
            int n = sigprocmask(SIG_SETMASK, &obset, nullptr);
            assert(n == 0);
            (void)n;
            cout << "解除2号信号的阻塞" << endl;

        }
    }
    return 0;
}

Linux信号之信号的保存,服务器,运维

可是我们并没有看到从1到0,这是因为进程直接终止了,在默认情况下,解除阻塞2号信号直接递达了,需要捕捉一下!

static void shouPending(sigset_t &pending)
{
    for (int sig = 1; sig <= 31; sig++)
    {
        if (sigismember(&pending, sig))
        {
            cout << "1";
        }
        else
        {
            cout << "0";
        }
    }
    cout << endl;
}

static void handler(int signum)
{
    cout<<"捕捉信号:"<<signum<<endl;
}
int main()
{
    //测试捕捉
    signal(2,handler);
    // 定义信号集
    sigset_t bset, obset;
    sigset_t pending;
    // 初始化
    sigemptyset(&bset);
    sigemptyset(&obset);
    sigemptyset(&pending);
    // 添加要进行屏蔽的信号
    sigaddset(&bset, 2);
    // 设置set到内核中
    int n = sigprocmask(SIG_BLOCK, &bset, &obset);
    assert(n == 0);
    cout << "2号信号以阻塞" << endl;
    (void)n;
    // 重复打印当前的pending信号集
    int count = 0;
    while (1)
    {
        // 获取当前进程的pending信号集
        sigpending(&pending);
        // 显示pending中的没有被递达的信号
        shouPending(pending);
        sleep(2);
        count++;
        if (count == 10)
        {
            int n = sigprocmask(SIG_SETMASK, &obset, nullptr);
            assert(n == 0);
            (void)n;
            cout << "解除2号信号的阻塞" << endl;

        }
    }
    return 0;
}

Linux信号之信号的保存,服务器,运维

这时我们就看到了当前进程的pending信号集从1变成了0!

还有一个小问题,貌似没有一个接口用来设置我们的pending位图,这是因为我们的所有发送信号的方式,都是修改pending位图的过程

3.问题三

如果我们对所有的信号都阻塞,我们是不是就写了一个不会被一场或者用户杀掉的进程?

static void shouPending(sigset_t &pending)
{
    for (int sig = 1; sig <= 31; sig++)
    {
        if (sigismember(&pending, sig))
        {
            cout << "1";
        }
        else
        {
            cout << "0";
        }
    }
    cout << endl;
}


static void blockSig(int signum)
{
    sigset_t bset;
    sigemptyset(&bset);
    sigaddset(&bset, signum);
    int n = sigprocmask(SIG_BLOCK, &bset, nullptr);
    assert(n == 0);
    (void)n;
}
int main()
{
    for(int sig=1;sig<=31;sig++)
    {
        blockSig(sig);
    }
    sigset_t pending;
    while(1)
    {
        sigpending(&pending);
        shouPending(pending);
        sleep(1);
    }
    return 0;
}

Linux信号之信号的保存,服务器,运维

和第一个问题是一样的,9号信号同样也不可以被阻塞!

同样的还有我们的19号暂停命令和20号命令!

所以最终结论,无论是9号信号就不可被捕捉和屏蔽的文章来源地址https://www.toymoban.com/news/detail-793543.html

到了这里,关于Linux信号之信号的保存的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • Linux服务器常见运维性能测试(1)综合跑分unixbench、superbench

    最近需要测试一批服务器的相关硬件性能,以及在常规环境下的硬件运行稳定情况,需要持续拷机测试稳定性。所以找了一些测试用例。本次测试包括在服务器的高低温下性能记录及压力测试,高低电压下性能记录及压力测试,常规环境下CPU满载稳定运行的功率记录。 这个系

    2024年02月04日
    浏览(82)
  • Linux本地部署1Panel服务器运维管理面板并实现公网访问

    1Panel 是一个现代化、开源的 Linux 服务器运维管理面板。高效管理,通过 Web 端轻松管理 Linux 服务器,包括主机监控、文件管理、数据库管理、容器管理等 下面我们介绍在Linux 本地安装1Panel 并结合cpolar 内网穿透工具实现远程访问1Panel 管理界面 执行如下命令一键安装 1Panel: 安

    2024年02月04日
    浏览(98)
  • [1Panel]开源,现代化,新一代的 Linux 服务器运维管理面板

    本期测评试用一下1Panel这款面板。1Panel是国内飞致云旗下开源产品。整个界面简洁清爽,后端使用GO开发,前端使用VUE的Element-Plus作为UI框架,整个面板的管理都是基于docker的,想法很先进。官方还提供了视频的使用教程,本期为大家按照本专栏的基本内容进行多方面的测评。

    2024年02月07日
    浏览(94)
  • Linux服务器常见运维性能测试(3)CPU测试super_pi、sysbench

    最近需要测试一批服务器的相关硬件性能,以及在常规环境下的硬件运行稳定情况,需要持续拷机测试稳定性。所以找了一些测试用例。本次测试包括在服务器的高低温下性能记录及压力测试,高低电压下性能记录及压力测试,常规环境下CPU满载稳定运行的功率记录。 这个系

    2024年02月02日
    浏览(55)
  • 华为云云耀云服务器L实例评测 | Linux系统宝塔运维部署H5游戏

    本章节内容,我们主要介绍华为云耀服务器L实例,从云服务的优势讲起,然后讲解华为云耀服务器L实例资源面板如何操作,如何使用宝塔运维服务,如何使用运维工具可视化安装nginx,最后部署一个自研的H5的小游戏(6岁的小朋友玩的很开心😁)。 前端的同学如果想把自己

    2024年02月07日
    浏览(58)
  • 运维:硬件服务器BMC介绍

    BMC(Baseboard Management Controller)是硬件服务器上的一个专用子系统,它允许管理员通过独立于主操作系统、CPU和主内存的远程管理工具来监视和管理服务器的硬件状态。这种接口通常用于远程监控和管理服务器,特别是在数据中心和大规模服务器部署环境中。 BMC接口规格: 接

    2024年04月12日
    浏览(53)
  • 运维——ssh无法登录云服务器

    一般来讲,无法登录ssh的原因挺多,如果无法登录云服务器,则除了要检查ssh端口是否放行,防火墙状态外,还需要检查云服务器web控制台入站规则是否开放了对应端口。如果你前面检查都是正常,那么还需要注意云服务器运营商。某些奇葩的运营商,例如TY云,限定了80,

    2024年02月01日
    浏览(65)
  • 运维:mysql常用的服务器状态命令

    目录 1、查询当前服务器运行的进程 2、查询最大链接数 3、查询当前链接数 4、展示当前正在执行的sql语句 5、查询当前MySQL当中记录的慢查询条数 6、展示Mysql服务器从启动到现在持续运行的时间 7、查询数据库存储占用情况 8、查询服务器启动以来的执行查询的总次数 9、查询

    2024年02月08日
    浏览(52)
  • 运维记录 会产生无用日志的服务器

    创建linux定时任务 crontab -e cron表达式 文件名.sh 查看linux定时任务 crontab -l 确认创建完成后重启cron service crond restart

    2024年04月11日
    浏览(46)
  • shell脚本——服务器巡检(自动化运维)

     目的   自动 获取集群内 多个主机 的内存、磁盘、cpu等信息 生成日志  准备    VMware虚拟主机IP在同一个网段(互相能ping通)             虚拟主机都有公钥免登录            修改主机IP  vi/etc/sysconfig/netwoek-scripts/ifcfg-ens160            设置主机名 hostnamectl set-ho

    2024年02月15日
    浏览(55)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包