2.25 sigprocmask函数使用 2.26sigaction信号捕捉函数 2.27SIGCHILD信号

news2024/11/13 3:43:21

2.25 sigprocmask函数使用

在这里插入图片描述
阻塞信号集有时称作信号掩码。
联想:fcntl函数可以修改fd属性。

./sigprocmask &  //将程序设置为后台运行,输入ls可以同步有输出
fg              //将程序恢复到前台运行
#include <stdio.h>
#include <signal.h>
#include <stdlib.h>
#include <unistd.h>

int main() {

    // 设置2、3号信号阻塞
    sigset_t set;
    sigemptyset(&set);
    // 将2号和3号信号添加到信号集中
    sigaddset(&set, SIGINT);
    sigaddset(&set, SIGQUIT);

    // 修改内核中的阻塞信号集
    sigprocmask(SIG_BLOCK, &set, NULL);

    int num = 0;

    while(1) {
        num++;
        // 获取当前的未决信号集的数据
        sigset_t pendingset;
        sigemptyset(&pendingset);
        sigpending(&pendingset);

        // 遍历前32位
        for(int i = 1; i <= 31; i++) {
            if(sigismember(&pendingset, i) == 1) {
                printf("1");//未决
            }else if(sigismember(&pendingset, i) == 0) {
                printf("0");//非未决
            }else {
                perror("sigismember");
                exit(0);
            }
        }

        printf("\n");
        sleep(1);
        if(num == 10) {
            // 解除阻塞,SIGINT默认动作是终止进程
            sigprocmask(SIG_UNBLOCK, &set, NULL);
        }

    }


    return 0;
}

2.26sigaction信号捕捉函数

相较于signal函数,优先使用sigaction信号捕捉函数。(标准的原因)
在这里插入图片描述
在这里插入图片描述

#include <sys/time.h>
#include <stdio.h>
#include <stdlib.h>
#include <signal.h>

void myalarm(int num) {
    printf("捕捉到了信号的编号是:%d\n", num);
    printf("xxxxxxx\n");
}

// 过3秒以后,每隔2秒钟定时一次
int main() {

    struct sigaction act;
    act.sa_flags = 0;
    act.sa_handler = myalarm;
    sigemptyset(&act.sa_mask);  // 清空临时阻塞信号集
   
    // 注册信号捕捉
    sigaction(SIGALRM, &act, NULL);

    struct itimerval new_value;

    // 设置间隔的时间
    new_value.it_interval.tv_sec = 2;
    new_value.it_interval.tv_usec = 0;

    // 设置延迟的时间,3秒之后开始第一次定时
    new_value.it_value.tv_sec = 3;
    new_value.it_value.tv_usec = 0;

    int ret = setitimer(ITIMER_REAL, &new_value, NULL); // 非阻塞的
    printf("定时器开始了...\n");

    if(ret == -1) {
        perror("setitimer");
        exit(0);
    }

    // getchar();//等待键盘录入
    while(1);

    return 0;
}

显示结果:
在这里插入图片描述

内核实现信号捕捉的过程

在这里插入图片描述

信号捕捉特性

1、假设信号捕捉到,信号捕捉代码仍在执行,又发送一个信号,该信号会被执行嘛?
这个信号不会被处理,阻塞在那!
未决信号集中SIGALRM信号为1,若处理myalarm函数,则未决信号集中SIGALRM信号为0,如果一直在处理,又产生一个SIGALRM信号,则它的未决信号标志位变成1,阻塞在那,不会执行回调函数。当上一次的回调函数执行完,第二个信号的回调函数才会被执行,它的未决信号标志位再次变成0。
在myalarm回调函数使用的过程当中,SIGALARM信号自动被屏蔽,不许我们设置,为系统行为,当回调函数执行结束,SIGALARM信号不被屏蔽。
2、执行回调函数时使用临时阻塞信号集,当回调结束使用内核当中的信号集。
3、常规信号阻塞的时候不支持排队。不支持记录有多少个信号被阻塞未决。其他34-64,30个实时信号支持排队。

2.27SIGCHILD信号

在这里插入图片描述
使用SIGCHLD信号解决僵尸进程的问题。
子进程结束时父进程有责任回收子进程的资源,一般不断循环调用wait(阻塞)或waitpid函数。实际过程中,父进程需要执行一些其他的操作,不可能一直阻塞等待回收子进程的资源。解决方案:捕捉SIGCHILD信号再调用wait(阻塞)或waitpid函数。
wait或waitpid函数一次只能回收一个子进程的资源。

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

void myFun(int num) {
    printf("捕捉到的信号 :%d\n", num);
    // 回收子进程PCB的资源
    //不使用while循环时,子进程回收不完全,未决信号集一次只能记录一个状态,产生的其余信号都被舍弃掉
    //死循环时,父进程一直被阻塞,不推荐
    // while(1) {
    //     wait(NULL); 
    // }
    while(1) {
       int ret = waitpid(-1, NULL, WNOHANG);
       if(ret > 0) {
           printf("child die , pid = %d\n", ret);
       } else if(ret == 0) {
           // 说明还有子进程或者
           break;
       } else if(ret == -1) {
           // 没有子进程
           break;
       }
    }
}

int main() {

    // 提前设置好阻塞信号集,阻塞SIGCHLD,因为有可能子进程很快结束,父进程还没有注册完信号捕捉
    sigset_t set;
    sigemptyset(&set);
    sigaddset(&set, SIGCHLD);
    sigprocmask(SIG_BLOCK, &set, NULL);

    // 创建一些子进程20个
    pid_t pid;
    for(int i = 0; i < 20; i++) {
        pid = fork();
        if(pid == 0) {//阻止孙进程的创建
            break;
        }
    }

    if(pid > 0) {
        // 父进程

        // 捕捉子进程死亡时发送的SIGCHLD信号
        struct sigaction act;
        act.sa_flags = 0;
        act.sa_handler = myFun;
        sigemptyset(&act.sa_mask);
        //信号捕捉还没有注册成功,子进程就已经结束?就会产生问题,不能回收子进程
        //需要提前设置好阻塞信号集,阻塞SIGCHLD
        sigaction(SIGCHLD, &act, NULL);

        // 注册完信号捕捉以后,解除阻塞
        sigprocmask(SIG_UNBLOCK, &set, NULL);

        while(1) {
            printf("parent process pid : %d\n", getpid());
            sleep(2);
        }
    } else if( pid == 0) {
        // 子进程
        printf("child process pid : %d\n", getpid());
    }

    return 0;
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/635622.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

动态规划dp —— 21.乘积最大子数组

1.状态表示 是什么&#xff1f;dp表中里的值所表示的含义就是状态表示 因为要考虑负数情况&#xff0c;负数乘以最大数就等于最小数了&#xff0c;负数乘以最小数就是最大数了 f[i]表示&#xff1a;以i位置为结尾的所以子数组中最大乘积 g[i]表会&#xff1a;以i位置为结尾…

Java 实现删除顺序表中第一次出现的某个元素

一、思路 1.顺序表不能是空的&#xff0c;如果顺序表是空的就肯定无法删除第一次出现的 key 元素. 2.定义一个key变量来传入要删除的元素&#xff0c;这个元素要求是第一次出现的. 3.删除之前要先找到第一次出现的key的下标. 4.找到位置之后就开始删除. 5.删除过程是从key下标位…

Linux - struct file与缓冲区

​​​​​​​ ​​​​​​​ 感谢各位 点赞 收藏 评论 三连支持 本文章收录于专栏【Linux系统编程】 ❀希望能对大家有所帮助❀ 本文章由 风君子吖 原创 ​​​​​​​ ​​​​​​​ ​​​​​​​ 前言 对于文件&#x…

DTS迁移Oracle至DM与MySQL至DM

目录 DTS迁移Oracle至DM... 3 一、前期准备... 3 二、DTS迁移... 4 1、新建工程... 5 2、新建迁移... 6 3、填写源库信息&#xff0c;使用指定驱动并自定义URL连接... 7 4、填写目标库信息... 8 5、填写迁移选项... 8 6、指定迁移模式及模式对象... 9 7、执行迁移...…

http长连接与会话保持

"我们半推半就的人生&#xff0c;没有和你一样被眷顾的未来!" 一、Http长连接 (1) 为什么需要长连接 如上展示的是一个常规得并不能再常规的http服务&#xff0c;从本地拉取远端linux上的本地文件上传至浏览器上&#xff0c;经过浏览器的渲染展示成如今的样子。唔&a…

【实战】体验训练Geneface

一.环境 conda activate geneface export PYTHONPATH./ CUDA_VISIBLE_DEVICES0 python tasks/run.py --configegs/datasets/lrs3/lm3d_syncnet.yaml --exp_namelrs3/syncnet 训练这篇出过的一些奇奇怪怪的问题基本上都记录在【环境搭建】40系一些奇奇怪怪的环境问题_weixin_50…

aigc - 文化衫设计

团队要用aigc设计个文化衫&#xff0c;就是给些提示词&#xff0c;然后让ai自动生成能够包含这些提示词的文化衫出来 二、第二版 思路&#xff1a;收集了30多张文化衫&#xff0c;然后用两种方式生成提升词&#xff1a;一个是自然语言描述这件t-short&#xff0c;一个是全名词…

IDEA常用插件Top18

前言&#xff1a;精心推荐给大家的一些日常开发中最常用的IDEA效率插件。 1、Alibaba Java Coding Guidelines代码规范检查工具 Alibaba Java Coding Guidelines ,阿里的一款强大的代码规范检查工具&#xff0c;可以让自己写出易读性更高的代码&#xff0c;可以让团队代码风格…

Keepalived+LVS

这里写目录标题 一、Keepalived及其工作原理1.1Keepalived体系主要模块及其作用1.3VRRP &#xff08;虚拟路由冗余协议&#xff09; 二、keepalived实验部署主服务器&#xff1a;备用服务器配置节点 一配置节点二 三、测试 一、Keepalived及其工作原理 Keepalived 是一个基于V…

Linux编译器 gcc、g++

绪论 你热爱生命吗&#xff1f;那幺别浪费时间&#xff0c;由于时间是组成生命的材料。——富兰克林 。 本篇文章写了主要写了Linux下编译器&#xff0c;以及编译器是如何实现编译的过程。 话不多说安全带系好&#xff0c;发车啦&#xff08;建议电脑观看&#xff09;。 附&…

2.30 守护进程(1) 2.31 守护进程(2)

2.30 守护进程&#xff08;1&#xff09; 终端 echo $$//查看当前终端的的pid tty//查看当前终端设备控制终端可以操作某一个进程。 进程组 会话 进程组、会话、控制终端之间的关系 find/2 查看2重定向到dev/null设备上&#xff0c;|管道&#xff08;创建子进程&#xff09…

RK3588平台开发系列讲解(USB篇)USB Device端口组合配置过程

文章目录 一、configfs二、configfs 配置过程2.1、使能相关的宏2.2、挂载configfs2.3、创建名为g1的usb复合设备2.4、配置PID和VID2.5、创建并配置strings子目录2.6、创建configuration和字符串2.7、创建functions2.8、将functions和configuration关联起来2.9、绑定到UDC,使能…

数据的存储练习题 -- (解题思路+代码)

目录 前言 知识补充 有符号和无符号的区别 练习一 练习二 练习三 练习四 练习五 练习六 练习七 前言 书接上回&#xff0c;我们学习了整形数据在内存中是怎么存储的。本篇我们就利用这些知识来做一些练习题目&#xff0c;把这些知识很好的消化掉。 知识补充 对…

简单的TCP网络程序·单进程

目录 文件1&#xff1a;tcpServer.cc 文件2&#xff1a;tcpServer.hpp 1.提出日志概念 -- 在后续完善 日志格式 -- 暂定简单的打印功能 2.创建套接字 SOCK_STREAM -- socket参数 3.bind自己的套接字 4.设置socket 为监听状态 * 新接口1&#xff1a;listen 函数1&…

IIC协议总结

IIC&#xff08;Inter-Integrated Circuit) &#xff0c;简单说就是IC&#xff08;芯片&#xff09;之间通信的总线。所谓总线&#xff0c;就是各个器件都并联到一组公共的线路上&#xff0c;然后共用这条线路来传输数据。总线的英文名为BUS&#xff0c;这是个形象的名字&#…

chatgpt赋能python:Python如何取三位数的每一位

Python如何取三位数的每一位 作为一门广泛应用的编程语言&#xff0c;Python在数值相关处理方面也十分得心应手。取三位数的每一位是一个常见的需求&#xff0c;那么在Python中该如何实现呢&#xff1f; 1. 数字字符串切片 Python中的字符串有索引和切片功能&#xff0c;我们…

chatgpt赋能python:Python如何命名输出图片名字

Python 如何命名输出图片名字 Python 是一种非常流行的编程语言。它非常灵活&#xff0c;可以用于各种应用场景。其中一个应用是图像处理。在 Python 中&#xff0c;我们可以使用不同的库来读取和处理图像。但是&#xff0c;当处理大量图片时&#xff0c;给每个图片命名会变得…

UDS关于0x37服务退出传输学习笔记

1.服务说明 客户端使用此服务来终止客户端和服务器之间的数据传输&#xff08;上传或下载&#xff09;。 2.请求消息 2.1请求消息子功能参数$Level&#xff08;LEV_&#xff09;定义 此服务不使用子函数参数。 2.2请求消息数据参数定义 transferRequestParameterRecord&a…

C++技能 - 详解const的几种使用【再也不迷糊了,干货还是蛮多的】

系列文章目录 C高性能优化编程系列 深入理解软件架构设计系列 高级C并发线程编程 C技能系列 期待你的关注哦&#xff01;&#xff01;&#xff01; 生活就是上帝发给你的一张手牌&#xff0c;无论多烂&#xff0c;你都得拿着。 Life is god give you a hand, no matter ho…

RK3588平台开发系列讲解(以太网篇)MDIO底层驱动

平台内核版本安卓版本RK3588Linux 5.10Android 12文章目录 一、mdiobus总线二、mdiobus的注册沉淀、分享、成长,让自己和他人都能有所收获!😄 一、mdiobus总线 mdio bus是mdio管里phy寄存器的总线,此总线非设备驱动模型之总线。mdiobus在内核中用mii_bus结构体描述,mii_b…