[Linux][OS][信号的捕捉] 可重入函数 | volatile | SIGCHLD信号

news2024/9/24 1:22:20

回顾:[Linux][OS][信号的保存和处理]

信号捕捉

1.sigaction

int sigaction(int signo, const struct sigaction *act, struct sigaction *oact);

参数:

    • signo:指定信号的编号
    • act:输入型参数,根据act修改该信号的处理动作
    • oact:输出型参数,通过oact传出该信号原来的处理动作

返回值:成功返回0,出错则返回- 1

act和oact指向sigaction结构体:

测试:

对函数指针结构体的存入

#include<iostream>
#include<cstring>
#include<unistd.h>
#include<signal.h>
using namespace std;
void handler(int signo)
{
    cout<<"catch a signal,signal number:"<<signo<<endl;
}
int main()
{
    struct sigaction act,oact;
    memset(&act,0,sizeof(act));//初始化
    memset(&oact,0,sizeof(oact));
    act.sa_handler=handler;
    sigaction(2,&act,&oact);
    while (true)
    {
        cout<<"i am a process:"<<getpid()<<endl;
        sleep(1);
        /* code */
    }
    return 0;
}

小 tip:memset 常用于初始化变量、清空缓冲区或者设置特定模式的字节序列。

  • 问题一: pending位图,什么时候从1->0.?

执行信号捕捉方法之前,先清0,在调用,来使信号再次产生时,当前信号完成了再执行下一个,禁止不断嵌套式的捕捉

当某个信号的处理函数被调用时,内核自动将当前信号加入进程的信号屏蔽字,提交到 block 表中

//循环模拟实现
void handler(int signo)
{
    cout << "catch a signal, signal number : " << signo << endl;
    while (true)
    {
        PrintPending();
        sleep(1);
    }
}
  • 问题2: 信号被处理的时候,对应的信号也会被添加到block表中,防止信号捕捉被嵌套调用

正在处理二号信号时,2 号信号会被屏蔽,那么如何也屏蔽其他信号呢?

    sigemptyset(&act.sa_mask);
    sigaddset(&act.sa_mask, 1);
    sigaddset(&act.sa_mask, 3);
    sigaddset(&act.sa_mask, 4);
    act.sa_handler = handler; // SIG_IGN SIG_DFL
    sigaction(2, &act, &oact);

如果 在调用信号处理函数时,除了当前信号被自动屏蔽之外,还希望自动屏蔽另外一些信号,则用sa_mask字段说明这些需 要额外屏蔽的信号,当信号处理函数返回时自动恢复原来的信号屏蔽字。

2.可重入函数

验证:链表的插入是不可重入的

  • insert 函数被
  • 节点丢失,内存泄露

如果一个函数,被重复进入的情况下,出错了或者可能出错,就是不可重入函数,否则就叫可重入函数

目前我们学到的大部分函数都是多执行流下的不可重入的:

  • 调用了malloc或free,因为malloc也是用全局链表来管理堆的。(例如 STL 不可以,涉及了很多指针的变换和扩容)
  • 调用了标准I/O库函数。标准I/O库的很多实现都以不可重入的方式使用全局数据结构。

3.volatile

测试

int flag = 0;
//volatile int flag=0;

void handler(int signo)
{
    cout << "catch a signal: " << signo << endl;
    flag = 1;
}

int main()
{
    signal(2, handler);
    // 在优化条件下, flag变量只在读取,可能被直接优化到CPU内的寄存器中
    while(!flag); // flag 0, !falg 真  逻辑运算

    cout << "process quit normal" << endl;
    return 0;
}

编译优化的设置:g++ -o $@$^ -O1 (0 1 2 3 对优化等级的选择)

  • 在优化条件下, flag变量只在读取可能被直接优化到CPU内的寄存器中
  • while(!flag); // flag 0, !falg 真 逻辑运算

改 1 优化后为什么就无法退出循环了?

因为优化,导致我们的内存不可见了!

这时添加 volatile 关键字:防止编译器过度优化,保持内存的可见性!

volatile int flag=0;

4.SIGCHLD 信号

子进程退出的时候,不是静悄悄的退出

子进程在退出的时候,会主动的向父进程发送 SIGCHLD(17)信号

怎么证明?基于信号捕捉,来对信号进行回收,将对 17 的回收加入到 handler 方法

void handler(int signo)
{
    pid_t rid;
   rid = waitpid(-1, nullptr, WNOHANG);//实现非阻塞调用
    cout << "I am proccess: " << getpid() << " catch a signo: " << signo << "child process quit: " << rid << endl;
}

int main()
{
    signal(17,handler);
    for (int i = 0; i < 10; i++)
    {
        pid_t id = fork();
        if (id == 0)
        {
            while (true)
            {
                cout << "I am child process: " << getpid() << ", ppid: " << getppid() << endl;
                sleep(5);
                break;
            }
            cout << "child quit!!!" << endl;
            exit(0);
        }
        sleep(1);
    }
    // father
    while (true)
    {
        cout << "I am father process: " << getpid() << endl;
        sleep(1);
    }

    return 0;
}

来进行调用测试:

得出子进程在进行等待的时候,我们可以基于信号的方式进行等待

等待的好处:

  1. 获取子进程的退出状态,释放子进程的僵尸
  2. 虽然不知道父子谁先运行,但是我们清楚,一定是 father 最后退出

还是要调用 wait 接口,father 必须保证自己是一致在运行的-->把子进程等待写入信号捕捉函数中

多个子进程该如何正确的回收呢?如果在退出一般的时候呢?while 循环+非阻塞方案

void handler(int signo)
{
    sleep(5);
    pid_t rid;
    while ((rid = waitpid(-1, nullptr, WNOHANG)) > 0)//非阻塞方案
    {
        cout << "I am proccess: " << getpid() << " catch a signo: " << signo << "child process quit: " << rid << endl;
    }
}

随机休眠时长进行测试:

#include <cstdlib> // 用于rand()和srand()
#include <ctime>   // 用于time()
srand(time(nullptr));      // 初始化随机数生成器
if (id == 0)
        {
            int random_sleep_time = rand() % 10 + 1; // 生成1到10之间的随机数
            cout << "Child process " << getpid() << " will sleep for " << random_sleep_time << " seconds." << endl;
            sleep(random_sleep_time);
            cout << "Child process " << getpid() << " is quitting." << endl;
            exit(0);
        }

实现边创建,边等待回收:

子进程在终止时会给父进程发SIGCHLD信号,该信号的默认处理动作是忽略SIG_DFL -> action -> IGN)事实上,由于UNIX 的历史原因,要想不产生僵尸进程还有另外一种办法:父进程调用sigaction将SIGCHLD的处理动作 置为SIG_IGN,这样fork出来的子进程在终止时会自动清理掉 signal(17,SIG_IGN);

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

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

相关文章

水果甜度个人手持设备检测-(题外:为啥会选型这个课题)

系列:水果甜度个人手持设备检测 -- 题外&#xff1a;为啥会选型这个课题 写在前面的话 这段时间一直也在思考&#xff0c;在主业之外哪些方向和产业成熟度较高、技术复杂度又不是很离谱&#xff0c;比较容易出成果的方向&#xff0c;能够有空去试着做一做。这几年AI智能化正…

Java方法02:方法的定义和调用

本节内容视频链接&#xff1a;Java方法03&#xff1a;方法的重载_哔哩哔哩_bilibilihttps://www.bilibili.com/video/BV12J41137hu?p47&vd_sourceb5775c3a4ea16a5306db9c7c1c1486b5 在Java中&#xff0c;‌‌方法的定义是创建一段可重复使用的代码块的过程‌。‌它…

Java 开发者 LLM 实战:利用 LangChain4j 打造高效本地 RAG 系统

1、引言 由于目前比较火的chatGPT是预训练模型&#xff0c;而训练一个大模型是需要较长时间&#xff08;参数越多学习时间越长&#xff0c;保守估计一般是几个月&#xff0c;不差钱的可以多用点GPU缩短这个时间&#xff09;&#xff0c;这就导致了它所学习的知识不会是最新的&…

代码随想录DAY17 - 二叉树 - 08/16

最大二叉树 题干 题目&#xff1a;给定一个不重复的整数数组 nums 。 最大二叉树 可以用下面的算法从 nums 递归地构建&#xff1a; 创建一个根节点&#xff0c;其值为 nums 中的最大值。 递归地在最大值 左边 的 子数组前缀上 构建左子树。 递归地在最大值 右边 的 子数组…

Linux下载卸载MySql

一. 安装Mysql 1.下载mysql --- 密钥 rpm --import https://repo.mysql.com/RPM-GPG-KEY-mysql-2022 rpm -ivh http://dev.mysql.com/get/mysql57-community-release-el7-10.noarch.rpm yum -y --enablerepomysql57-community install mysql-community-server 2.启动mysql sy…

如何选择最佳智能排班系统?9款工具全解析

本文介绍的自助排班管理工具有Moka、红圈排班、工作易排班、泛微e-office、Udesk、畅捷通T、Zenefits、Homebase、Deputy。 在管理团队时&#xff0c;手动排班不仅耗时&#xff0c;还容易出错&#xff0c;影响工作效率&#xff0c;相信很多管理者也有同样的困扰。为了解决这个痛…

【Spring Boot】定时任务

目录 前言 定时任务注解Scheduled 设计一个定时任务 1.启用定时任务 2.创建定时任务 Cron 表达式详解 多线程定时任务 总结 定时任务框架xxl-job SpringBoot继承定时任务框架 1.搭建调度中心xxl-job-admin 1.1下载项目 1.2修改配置文件端口和数据库代码 1.3连接到…

Linux进程间通信学习记录(无名管道)

0.Linux进程间通信的方式 &#xff08;1&#xff09;.从UNIX继承过来的通信方式 无名管道&#xff08;pipe&#xff09; 有名管道&#xff08;fifo&#xff09; 信号&#xff08;signal&#xff09; &#xff08;2&#xff09;.System V IPC 共享内存 消息队列 信号灯集 &am…

Java方法03:方法的重载

本节内容视频链接&#xff1a;https://www.bilibili.com/video/BV12J41137hu?p47&vd_sourceb5775c3a4ea16a5306db9c7c1c1486b5https://www.bilibili.com/video/BV12J41137hu?p47&vd_sourceb5775c3a4ea16a5306db9c7c1c1486b5 在Java中&#xff0c;‌方法的重载&#x…

AI编程系列一1小时完成链家房价爬虫程序

背景 AI编程实在太火&#xff0c;写了很多年的Java&#xff0c;现在Python 和Go 简单好用&#xff0c;今天结合智谱清言快速完成一个程序爬虫程序&#xff0c;没有任何Python 编程经验&#xff0c;只需要会提问&#xff0c;熟悉简单HTML结构即可。未来一定是有业务能力者的福…

Anylogic设置颜色

三维对象的颜色修改 以detector智能体为例&#xff0c;颜色修改代码为&#xff1a; detector.setColor(“Material_(4)_Surf”,blue); 二维对象的颜色修改 house智能体为例&#xff0c;对组件内的_ps282填充的颜色进行修改&#xff0c;level_是该智能体已有的参数或者称之为变…

CLRerNet推理详解及部署实现(下)

目录 前言一、CLRerNet推理(Python)1. CLRerNet预测2. CLRerNet预处理3. CLRerNet后处理4. CLRerNet推理 二、CLRerNet推理(C)1. ONNX 导出2. CLRerNet预处理3. CLRerNet后处理4. CLRerNet推理 三、CLRerNet部署1. 源码下载2. 环境配置2.1 配置CMakeLists.txt2.2 配置Makefile …

python:画由抛物线: y^2=2x 与直线 y=x-4 所围成的图形

《高等数学》同济大学版 P339 编写 test_diff_3_area.py 如下 # -*- coding: utf-8 -*- """ 画由抛物线: y^22x 与直线 yx-4 所围成的图形 """ import numpy as np import matplotlib.pyplot as plt from matplotlib.patches import Polygon…

11结构型设计模式——外观模式

一、外观模式简介 外观模式&#xff08;Facade Pattern&#xff09;是一种结构型设计模式&#xff0c;它提供了一个统一的接口来访问子系统中的一组接口&#xff0c;使得子系统的使用更加简单和方便。通过外观模式&#xff0c;可以将复杂的子系统封装在一个外观类&#xff08;…

​​数据结构-树

n = 度数之和 + 1 n + x + y + z = x +2y +3z + 1

增加练习(修改获取练习的基本信息接口)

文章目录 1.sun-club-practice-api1.enums1.CompleteStatusEnum.java 2.req1.GetPracticeSubjectsReq.java 3.vo1.PracticeSubjectListVO.java 2.sun-club-practice-server1.PracticeSetController.java2.service1.PracticeSetServiceImpl.java 3.dao1.PracticeDao.java2.Pract…

HAL STM32 SG90舵机驱动控制

HAL STM32 SG90舵机驱动控制 &#x1f516;测试对象&#xff1a;STM32F103SG90舵机 &#x1f33c;功能实现&#xff1a;通过串口指令&#xff0c;控制SG90舵机转动到指定角度。 ✨在实际硬件舵机驱动过程中&#xff0c;使用SG90普通舵机空载运转情况下&#xff0c;电流在180mA…

验证集的loss比训练集大得多Val Loss is too large

这个跟数据集有关&#xff0c;不过可已通过clip减缓。 解决方法 nn.utils.clip_grad_norm_(self.Model.parameters(), max_norm5)

AtCoder Regular Contest 182 A~D

A.Chmax Rush!&#xff08;枚举&#xff09; 题意&#xff1a; 有一个长度为 N N N的整数序列 S S S。最初&#xff0c; S S S的所有元素都是 0 0 0。 同时给你两个长度为 Q Q Q的整数序列&#xff1a; P ( P 1 , P 2 , … , P Q ) P(P_1,P_2,\dots,P_Q) P(P1​,P2​,…,PQ…

AI产品经理修炼指南:从青铜到王者的逆袭之路

一、AI通识 1.1 AI产业结构 AI发展至今大致按照在产业结构上的分工不同产生了三种类型的公司&#xff0c;我们在转型时最好要先明确自己的优势及兴趣&#xff0c;来判断自己适合着眼于哪个层面的工作&#xff0c;从而进行针对性的学习和提升。 &#xff08;1&#xff09;行业…