[ Linux ] 可重入函数,volatile 关键字,SIGCHLD信号

news2024/11/20 18:20:58

目录

1.可重入函数

2.volatile

2.1从信号角度理解volatile的作用

2.2volatile的作用

3.SIGCHLD信号

3.1SIGCHLD信号的验证


1.可重入函数

在数据结构初阶时我们学习过链表,其中当然也学习过链表头插。在此我们复习一下链表头插,我们使用画图来演示。

newnode->next = head->next;
head->next = newnode;

下面我们假设今天main执行流只在执行insert函数向一个链表head中插入节点node1,插入操作分为两步,刚做完第一步的 时候,因为硬件中断使进程切换到内核,再次回用户态之前检查到有信号待处理,于是切换 到sighandler函数,sighandler也调用insert函数向同一个链表head中插入节点node2,插入操作的 两步都做完之后从sighandler返回内核态,再次回到用户态就从main函数调用的insert函数中继续 往下执行,先前做第一步之后被打断,现在继续做完第二步。结果是,main函数和sighandler先后 向链表中插入两个节点,而最后只有一个节点真正插入链表中了。(下图为例)

 

像上例这样,insert函数被不同的控制流程调用,有可能在第一次调用还没返回时就再次进入该函数,这称

重入,insert函数访问一个全局链表,有可能因为重入而造成错乱,像这样的函数称为 不可重入函数,反之,

如果一个函数只访问自己的局部变量或参数,则称为可重入(Reentrant) 函数

因此如果一个函数符合以下条件之一则是不可重入的:

  • 调用了malloc或free,因为malloc也是用全局链表来管理堆的。
  • 调用了标准I/O库函数,标准I/O库的很多实现都以不可重复的方式使用全局数据结构。

2.volatile

2.1从信号角度理解volatile的作用

今天我们站在信号的角度上理解一下valatile。

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

int flags = 0;

void handler(int signo)
{
    flags = 1;
    printf("flags: 0 -> 1\n");
}

int main()
{
    signal(2,handler);
    while(!flags);
    printf("进程是正常退出的! flags: %d \n",flags);
    return 0;
}

我们来看一下这段简单的C语言代码,在标准情况下,程序运行起来时,键入CTRL-C,2号信号被捕捉,执行自定义动作,修改flags=1,while条件不满足,退出循环,进程退出。

但是,我们注意while(!flags)这条语句是检测,是逻辑判断。因此由CPU进行,每次循环检测都要读一下flags这个值,在正常情况下就应该这么做。但是当编译器优化等级很高时,在当前执行流下对flags没有做任何修改,因此会把flags这个值优化到CPU的寄存器内,因此在后续的判断中,CPU只会读取寄存器内flags内的值。但是当我们键入ctrl-c时,向进程发送2号信号。进程捕捉到2号信号会自定义调用handler方法。会将flags的值由0->1,这里注意由于flags是存在内存中的,我们改变的是内存中flags的值,而CPU寄存器内flags的值却没有变。因此CPU读取的flags的值却并没有变。所以当我们键入ctrl-c时,while循环也是不结束的。进程也不会退出。

myproc:myproc.c
	gcc -o $@ $^ -O2

.PHONY:clean
clean:
	rm -f myproc

gcc中有不同的优化等级,我们在makefile中使用-O2 对gcc编译器进行优化。

我们再次将程序运行起来

那么如何解决呢,我们可以使用volatile关键字。volatile关键字就是要告诉编译器,不准对flags做任何优化,每次CPU计算的时候,拿内存的数据,都必须在内存中拿。

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

//保持内存的可见性
volatile int flags = 0;

void handler(int signo)
{
    flags = 1;
    printf("flags: 0 -> 1\n");
}

int main()
{
    signal(2,handler);
    while(!flags);
    printf("进程是正常退出的! flags: %d \n",flags);
    return 0;
}

2.2volatile的作用

根据上面的例子我们可以总结出volatile的作用:

  • volatile作用:保持内存的可见性,告知编译器,该关键字修饰的变量,不允许被优化,对该变量的任何操作,都必须在真实的内存中进行操作。

3.SIGCHLD信号

在进程一章时,我们知道进程退出。其中,子进程退出的时候,不是默默地退出。而是会给父进程发送一个信号。这个信号就是SIGCHLD信号。该信号的默认处理动作是忽略,父进程可以自定义SIGCHLD信号的处理函数。这样父进程只需专心处理自己的工作,不必关心子进程了,子进程终止时会通知父进程,父进程在信号处理函数中调用wait清理子进程即可。

3.1SIGCHLD信号的验证

我们用C++代码来验证一下当子进程退出时,父进程捕捉SIGCHLD信号。这段代码也不难......

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

using namespace std;

void handler(int signo)
{
    cout<<"子进程退出啦,我确实收到了信号"<<signo<<"我是: pid: "<<getpid()<<endl;
}

int main()
{
    signal(SIGCHLD,handler);
    pid_t id = fork();
    if(id == 0)
    {
        //child
        while(true)
        {
            cout<<"我是子进程:"<<getpid()<<endl;
            sleep(1);
        }
        exit(0);
    }

    //parent
    while(true)
    {
        cout<<"我是父进程:"<<getpid()<<endl;
        sleep(1);
    }
    return 0;
}

 

我们使用man 7 siganl查看信号发现,SIGCHLD不仅当子进程退出时可以返回给父进程,也可以当子进程暂停。

 

我们再来验证一下暂停,我们发送19号信号是暂停进程,18号信号是恢复进程

 

此时我们来查看当子进程暂停时的状态,我们可以使用下面命令查看

ps axj | grep myproc

  

如果我们杀掉子进程查看状态:发现子进程一进僵尸

注:事实上,由于UNIX 的历史原因,要想不产生僵尸进程还有另外一种办法:父进程调 用sigaction将SIGCHLD的处理动作置为SIG_IGN,这样fork出来的子进程在终止时会自动清理掉,不 会产生僵尸进程,也不会通知父进程。系统默认的忽略动作和用户用sigaction函数自定义的忽略 通常是没有区别的,但这是一个特例。此方法对于Linux可用,但不保证在其它UNIX系统上都可用。

(本篇完)

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

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

相关文章

Koa初体验

前面我们已经学习了express&#xff0c;另外一个非常流行的Node Web服务器框架就是Koa。 Koa官方的介绍&#xff1a; koa&#xff1a;next generation web framework for node.js&#xff1b; koa&#xff1a;node.js的下一代web框架&#xff1b; 事实上&#xff0c;koa是ex…

【云计算与大数据技术】Google、亚马逊、IBM、阿里云等云计算应用平台介绍讲解(超详细)

云应用跟云计算最大的不同在于&#xff0c;云计算作为一种宏观技术发展概念而存在&#xff0c;而云应用则是直接面对客户解决实际问题的产品。 “云应用”的工作原理是把传统软件“本地安装、本地运算”的使用方式变为”即取即用”的服务&#xff0c;通过互联网或局域网连接并操…

VUE学习(五)VUE项目发布启动

在项目目录下运行 npm run build 2.下载nginx nginx: download 双击nginx.exe运行 3.将打包好的vue项目下dist目录所有文件拷贝 4.粘贴至nginx目录html下 5.此时在浏览器中输入localhost 即可看到发布的网站了

【云计算与大数据技术】大数据概念和发展背景讲解(图文解释 超详细)

一、什么是大数据 大数据是一个不断发展的概念&#xff0c;可以指任何体量或负载下那个超出常规数据处理方法和处理能力的数据&#xff0c;数据本身可以是结构化&#xff0c;半结构化甚至是非结构化的&#xff0c;随着物联网技术与可穿戴设备的飞速发展&#xff0c;数据规模变…

首篇!BEV-Locator:多目端到端视觉语义定位网络(清华轻舟智航)

点击下方卡片&#xff0c;关注“自动驾驶之心”公众号ADAS巨卷干货&#xff0c;即可获取点击进入→自动驾驶之心【SLAM】技术交流群后台回复【BEV定位】获取本文论文&#xff01;摘要准确的定位能力是自动驾驶的基础。传统的视觉定位框架通过几何模型来解决语义地图匹配问题&am…

【C语言经典面试题】这样的char * 定义怎么回事

作者简介 *架构师李肯&#xff08;全网同名&#xff09;**&#xff0c;一个专注于嵌入式IoT领域的架构师。有着近10年的嵌入式一线开发经验&#xff0c;深耕IoT领域多年&#xff0c;熟知IoT领域的业务发展&#xff0c;深度掌握IoT领域的相关技术栈&#xff0c;包括但不限于主流…

Cookie | Cookie的理论基础、Cookie中常用的方法

目录 一&#xff1a;Cookie的理论基础 二&#xff1a;Cookie中常用的方法 一&#xff1a;Cookie的理论基础 &#xff08;1&#xff09;cookie怎么生成&#xff1f; ①session的实现原理中&#xff0c;每一个session对象都会关联一个sessionid&#xff0c;例如&#xff1a;JS…

中创软件递交上会稿:年营收不到2亿 税收优惠占利润比高

雷递网 雷建平 12月10日山东中创软件商用中间件股份有限公司&#xff08;简称&#xff1a;“中创软件”&#xff09;日前递交上会稿&#xff0c;准备在科创板上市。中创软件计划募资6亿元&#xff0c;其中&#xff0c;2.3亿元用于应用基础设施及中间件研发项目&#xff0c;1.3亿…

开源一个各种USB电缆的测试仪,再也不用担心被只有充电功能的数据线坑了

作者&#xff1a;晓宇&#xff0c;排版&#xff1a;晓宇微信公众号&#xff1a;芯片之家&#xff08;ID&#xff1a;chiphome-dy&#xff09;01 想知道你的USB Type C数据线是USB2或者USB3吗&#xff1f;大家是否有一些仅有充电功能的USB数据线在你的抽屉里&#xff0c;等待某个…

量子计算(十三):量子计算的if和while

文章目录 量子计算的if和while 一、基于测量的跳转 二、基于量子信息的IF和WHILE 量子计算的if和while 所谓量子线路&#xff0c;从本质上是一个量子逻辑门的执行序列&#xff0c;它是从左至右依次执行的。即使介绍了函数调用的思想&#xff0c;也可以理解为这是一种简单地…

10-11-12 - 实模式到保护模式

---- 整理自狄泰软件唐佐林老师课程 文章目录1. 从计算机的历史谈起2. 绝对的权利带来的问题3. CPU历史的里程碑 - 80863.1 深入解析 [段地址 : 偏移地址]3.1.1 示例3.1.2 问题3.2 8086时期应用程序中的问题3.3 思考4. 80286的登场4.1 80286的兼容性4.2 初识保护模式4.2.1 描述…

JDBC连接数据库详解~

课前导读&#xff1a; 本文章有关JDBC连接数据库的操作&#xff0c;其中涉及了编译器idea的使用&#xff0c;其中连接的数据库为MySQL数据库&#xff0c;通过博主自己的学习和总结写出了下面的文章。 目录 课前导读&#xff1a; 一、JDBC简介 二、JDBC连接操作 三、源码提供…

数素数

目录 1013 数素数 输入格式&#xff1a; 输出格式&#xff1a; 输入样例&#xff1a; 输出样例&#xff1a; 代码长度限制: 时间限制: 内存限制: 思路: 1.判断素数 1.2素数判断代码: 2.数组存素数 2.2存素数代码: 3.输出Pm到Pn的全部素数 3.2代码 总代码: 总结: 题目…

Web大学生网页作业成品 bootstrap响应式网站开发 基于HTML+CSS+JS+Bootstrap制作火锅美食网站(4页)

&#x1f380; 精彩专栏推荐&#x1f447;&#x1f3fb;&#x1f447;&#x1f3fb;&#x1f447;&#x1f3fb; ✍️ 作者简介: 一个热爱把逻辑思维转变为代码的技术博主 &#x1f482; 作者主页: 【主页——&#x1f680;获取更多优质源码】 &#x1f393; web前端期末大作业…

非零基础自学计算机操作系统 第1章 操作系统概述 1.4 操作系统的分类 1.4.3 实时操作系统 1.4.4 通用操作系统 1.4.5 单用户操作系统

非零基础自学计算机操作系统 文章目录非零基础自学计算机操作系统第1章 操作系统概述1.4 操作系统的分类1.4.3 实时操作系统1.4.4 通用操作系统1.4.5 单用户操作系统第1章 操作系统概述 1.4 操作系统的分类 1.4.3 实时操作系统 所谓实时&#xff0c;是指系统能够对外部请求做…

R语言多重比较方法

假设检验的基本原理是小概率原理&#xff0c;即我们认为小概率事件在一次试验中实际上不可能发生。 多重比较的问题 当同一研究问题下进行多次假设检验时&#xff0c;不再符合小概率原理所说的“一次试验”。如果在该研究问题下只要有检验是阳性的&#xff0c;就对该问题下阳性…

c#入门-静态引用,扩展方法

静态引用 声明静态引用 引用命名空间时&#xff0c;可以在using后面加static修饰符。 然后把要引用的命名空间改为带命名空间的一个具体的类。 这称为静态引用。 using static System.Int32; using static System.Console; int a Parse(ReadLine());静态引用的效果 静态引…

VRC改模从入门到入门

第一步入门 从unity开始 bilibili超细心的unity入门教程 虽然视频很长&#xff0c;但是从p1看到p41就行&#xff0c;脚本部分完全不需要看&#xff0c;因为vrc上传会过滤掉不是他们的脚本的。 unity下载一定要下载2019.4.31f1版本&#xff0c;哔哩哔哩教程有下载unity对应版本…

基于Android的外卖App系统设计

基于Android的外卖App系统设计 摘要 随着智能手机的快速普及&#xff0c;智能手机操作系统市场风生水起。为了让智能手机用户能够随时随地查询互联网所提供的服务&#xff0c;一种高效的办法就是将应用系统的功能拓展到手机终端上&#xff0c;让手机能够通过移动网以及互联网…

CentOS 安装 mysql 8.0

目录 下载 安装步骤 上传 解压安装 参考资料 补充报错解决 下载 MySQL :: Download MySQL Community Serverhttps://dev.mysql.com/downloads/mysql/ 安装步骤 上传 使用xshell&#xff0c;连接服务器&#xff0c;用 rz命令接收下载的文件&#xff08;该命令使用 yum…