【hello Linux】可重入函数、volatile和SIGCHLD信号

目录

1. 可重入函数

2. volatile

3. SIGCHLD信号


Linux!🌷 

1. 可重入函数

先来谈一下重入函数的概念:重入函数便是在该函数还没有执行完毕便重复进入该函数(一般发生在多线程中);

可重入函数:一个函数一旦重入,对原函数功能不会出现问题(内存泄漏等);

不可重入函数:一个函数一旦重入,对原函数功能有可能出现问题;

什么意思呢?下面给一个具体的例子方便大家理解:

  • main函数调用insert函数向一个链表head中插入节点node1,插入操作分为两步,刚做完第一步的时候,因为硬件中断使进程切换到内核,再次回用户态之前检查到有信号待处理,于是切换到sighandler函数,sighandler也调用insert函数向同一个链表head中插入节点node2,插入操作的 两步都做完之后从sighandler返回内核态,再次回到用户态就从main函数调用的insert函数中继续 往下执行,先前做第一步之后被打断,现在继续做完第二步。结果是,main函数和sighandler先后向链表中插入两个节点,而最后只有一个节点真正插入链表中了。
  • 像上例这样,insert函数被不同的控制流程调用,有可能在第一次调用还没返回时就再次进入该函数,这称为重入,insert函数访问一个全局链表,有可能因为重入而造成错乱,像这样的函数称为不可重入函数,反之,如果一个函数只访问自己的局部变量或参数,则称为可重入(Reentrant) 函数。
如果一个函数符合以下条件之一则是不可重入的 :
  • 调用了mallocfree,因为malloc也是用全局链表来管理堆的。
  • 调用了标准I/O库函数。标准I/O库的很多实现都以不可重入的方式使用全局数据结构。

注意:可重入函数/不可重入函数,只是一种特性而已,并无优劣好坏之分;

2. volatile

volatile其实是C语言中的一个关键字,还是比较冷门的,虽然冷门但不意味着不重要;

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

下面给出几个例子方便大家理解:

示例一: 

  #include <stdio.h>    
  #include <signal.h>                                                                                                                                           
      
  int flag = 0;    
      
  void handler(int signo)    
  {    
    printf("change flag 0 to 1!\n");    
    flag = 1;    
  }    
      
  int main()    
  {    
    signal(2,handler);    
    while(!flag);    
    printf("process quit normal!\n");    
    return 0;    
  }    

标准情况下,键入 CTRL-C ,2号信号被捕捉,执行自定义动作,修改 flag=1 , while 条件不
满足,退出循环,进程退出;

示例二:gcc 进行一定程度的优化

对 makefile 文件进行修改再编译,-O3表示优化级数; 

优化情况下,键入 CTRL-C ,2号信号被捕捉,执行自定义动作,修改 flag=1 ,但是 while 条
件依旧满足,进程继续运行!但是很明显flag肯定已经被修改了,但是为何循环依旧执行?很
明显, while 循环检查的flag,并不是内存中最新的flag,这就存在了数据二异性的问题。
while 检测的flag其实已经因为优化,被放在了CPU寄存器当中。

示例三:volatile进行修饰

  #include <stdio.h>    
  #include <signal.h>    
      
  volatile int flag = 0;                                                                                                                           
      
  void handler(int signo)    
  {    
    printf("change flag 0 to 1!\n");    
    flag = 1;    
  }    
      
  int main()    
  {    
    signal(2,handler);    
    while(!flag);    
    printf("process quit normal!\n");    
    return 0;    
  }   

可以看到结果正确;

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

vloatile 还有一个作用:防止指令重排(一条C/C++指令进行编译后可能形成多条汇编代码,

volatile可保证多条汇编代码的顺序不会发生改变),这个了解下就好;

 3. SIGCHLD信号

进程一章讲过用 wait waitpid 函数清理僵尸进程 , 父进程可以阻塞等待子进程结束 , 也可以非阻
塞地查询是否有子进程结束等待清理(也就是轮询的方式) 。采用第一种方式 , 父进程阻塞了就
不能处理自己的工作了;采用第二种方式 , 父进程在处理自己的工作的同时还要记得时不时地轮
询一 下, 程序实现复杂。
其实, 子进程在终止时会给父进程发 SIGCHLD 信号 , 该信号的默认处理动作是忽略, 父进程
可以自定义 SIGCHLD 信号的处理函数, 这样父进程只需专心处理自己的工作, 不必关心子进
程了, 子进程终止时会通知父进程 , 父进程在信号处理函数中调用wait 清理子进程即可。
事实上 , 由于 UNIX 的历史原因 , 要想不产生僵尸进程还有另外一种办法 : 父进程调用 sigaction
SIGCHLD 的处理动作置为SIG_IGN, 这样 fork 出来的子进程在终止时会自动清理掉 , 不会产生
僵尸进程 , 也不会通知父进程。系统默认的忽略动作和用户用sigaction 函数自定义的忽略通常
是没有区别的 , 但这是一个特例。此方法对于 Linux 可用 , 但不保证在其它UNIX 系统上都可用。

下面编写代码对上述所说的内容进行一个验证:

代码1:子进程在退出时候会发送SIGCHLD信号?

#include <stdio.h>    
#include <unistd.h>    
#include <signal.h>    
                                                                                            
void handler(int signo)    
{    
  printf("get a signal,signo:%d\n",signo);    
}    
    
int main()    
{    
  //对信号捕捉    
  signal(SIGCHLD,handler);    
    
  //创建子进程    
  if(fork()==0)    
  {    
    //child    
    printf("I am a child,I quit...!\n");    
    sleep(1);    
    return 0;    
  }    
  //parent    
  while(1)    
  {    
    ;    
  }    
  return 0;    
}    

 经过证实,子进程在退出时会发送 17)SIGCHLD 信号;

代码2:可以在SIGCHLD自定义捕捉时,waitpid子进程?

#include <stdio.h>    
#include <signal.h>    
#include <unistd.h>    
#include <sys/types.h>    
#include <sys/wait.h>    
    
void handler(int signo)    
{    
  printf("get a signal!signo:%d\n",signo);    
  sleep(1);    
  while(1)    
  {    
    waitpid(-1,NULL,WNOHANG);    
  }    
}    
    
int main()    
{    
  //捕捉信号    
  signal(SIGCHLD,handler);    
  //创建子进程    
  if(fork()==0)    
  {    
    //child    
    printf("I am a child!\n");    
    sleep(1);    
    return 0;                                                         
  }    
  while(1);    
  return 0;    
}    

 由上我们可以看到子进程的3种状态的切换,S(在1S输出I am a child)——>Z(sleep1S后才waitpid)——>被清理;

代码3:直接在收到SIGCHLD时,进行忽略处理,不形成僵尸,直接处理;

#include <stdio.h>    
#include <signal.h>    
#include <unistd.h>    
#include <sys/types.h>    
#include <sys/wait.h>    
    
int main()    
{    
  //捕捉信号    
  signal(SIGCHLD,SIG_IGN);                                                             
  //创建子进程    
  if(fork()==0)    
  {    
    //child    
    printf("I am a child!\n");    
    sleep(1);    
    return 0;    
  }    
  while(1);    
  return 0;    
}    

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

【私有云底层】理解OpenStack核心组件

文章目录 &#x1f479; 关于作者一、Keystone 身份认证服务Keystone 架构工作流程 二、Glance 镜像服务Glance 架构磁盘与容器Glance 工作流程 三、Placement 放置服务Placement 工作流程 四、Nova 计算服务Nova 架构Nova 工作流程 五、Neutron 网络服务Neutron 架构Neutron 支…

浅谈测试用例设计 | 京东云技术团队

作者&#xff1a;京东物流 王莹莹 一、测试用例为什么存在 1.1 定义 测试用例(Test Case)是指对特定的软件产品进行测试任务的描述&#xff0c;体现测试方案、方法、技术和策略。测试用例内容包括测试目标、测试环境、输入数据、测试步骤、预期结果、测试脚本等&#xff0c;…

FreeRTOS系统学习第一步:新建 FreeRTOS 工程—软件仿真

创建一个FreeRTOS系统工程 1.新建工程文件夹2.Keil新建工程2.1 New Project2.2 Select Device For Target2.3 Manage Run-Time Environment 3. 在 KEIL 工程里面新建文件组3.1在 KEIL 工程里面添加文件 4. 编写 main 函数5. 调试配置5.1 设置软件仿真5.2 修改时钟大小在时钟相关…

基于python的socket网络通信【1】

一、Socket原理 学习了大佬的知识&#xff0c;简单记一些笔记 https://www.jianshu.com/p/066d99da7cbd http://c.biancheng.net/view/2351.html 1.1什么是Socket 在计算机通信领域&#xff0c;socket 被翻译为“套接字”&#xff0c;它是计算机之间进行通信的一种约定或一种…

计算机网路常见面试题(上)

计算机网络基础 # 网络分层模型 # OSI 七层模型是什么&#xff1f;每一层的作用是什么&#xff1f; OSI 七层模型 是国际标准化组织提出一个网络分层模型&#xff0c;其大体结构以及每一层提供的功能如下图所示&#xff1a; 每一层都专注做一件事情&#xff0c;并且每一层都…

网络安全:namp扫描工具

-sP可以扫描一个网段ip以及状态和基本信息&#xff0c;10.1.1.2-3就是扫描2和3这两个ip的主机 -p可以扫描指定ip对应主机的端口号&#xff0c;可以是一个范围 nmap简单扫描&#xff1a;nmap 地址 检查地址是否在线以及open的端口号 在端口开放&#xff0c;不一定可以与对方正常…

Spring 依赖注入源码

文章目录 依赖注入原始依赖注入方式注解方式寻找注入点注入点进行注入 从BeanFactory中找注入对象总结 依赖注入 具体代码是在AbstractAutowireCapableBeanFactory类的populateBean()方法&#xff0c;此方法中主要做的事情如下&#xff1a; 实例化之后&#xff0c;调用Instan…

各大外卖平台占据共享经济市场主要份额,占比近50%

哈喽大家好&#xff0c;随着大量互联网用户和移动支付的普及、大量用户通过共享平台将闲置资源和服务与需求方进行匹配&#xff0c;实现了资源的高效利用和消费者福利的提升。在全球化驱动的新型消费需求以及政策支持下&#xff0c;共享经济正在向更加成熟和规范化的方向发展。…

瑞芯微RK3568智慧视频录像机NVR设备解决方案

NVR技术应用功能模式&#xff0c;较为灵活且能够在很大程度上满足当今视频监控系统功能需求。以NVR技术为核心的小型NVR方案&#xff0c;具有规模较小、操作灵活、使用方便、经济实用等优点&#xff0c;其前端主要配合高清视频摄像机支持8路720P的高清视频图像接入&#xff0c;…

13-NumPy

文章目录 一.基础1.Ndarray对象2.数据类型 二.数组1.数组属性&#xff08;1&#xff09;arange&#xff08;2&#xff09;shape&#xff08;3&#xff09;ndim&#xff08;4&#xff09;itemsize 2.创建数组&#xff08;1&#xff09;empty&#xff08;2&#xff09;zero&#…

Chat GPT在全球变暖中的潜在应用

01 摘要 气候变化是一个全球性的重大挑战&#xff0c;需要整合包括大气科学、海洋学和生态学在内的许多不同科学领域。解决这一问题的复杂性和规模需要利用先进的工具和技术来理解、建模和预测未来的气候状况。人工智能和自然语言处理技术&#xff0c;如Chat GPT&#xff0c;…

Maven 依赖下载失败解决方案——配置国内源 + 具体解决办法

目录 前言 一、配置 Maven 国内源 二、重新下载jar包 三、其他问题 前言 最近发现 spring-boot 框架更新到 2.7.11 了&#xff0c;由于以前一直使用的是 2.7.9 &#xff0c;所以一直出现依赖下载失败的问题&#xff0c;实际上这是由于 IDEA 会先加载之前下载好的依赖&#xf…

Linux操作系统命令大全

Linux是一种操作系统 Operating System 简称 OS &#xff0c;是软件的一部分&#xff0c;它是硬件基础上的第一层软件&#xff0c;是硬件和其它软件沟通的桥梁。 操作系统会控制其他程序运行&#xff0c;管理系统资源&#xff0c;提供最基本的计算功能&#xff0c;如管理及配置…

业内常用即时传输网盘

工具名称 业内常用即时传输网盘 功能简介 无需登录&#xff0c;短时间内有效&#xff0c;多用于传输小型敏感文件 外部链接 请见文内 内部网盘链接 在线站点&#xff0c;无网盘链接 使用说明 许多安全行内人士在团队内互传敏感文件时&#xff0c;为实现上传和下载文件…

现场工程师救火-UEFI(BIOS)节能设置导致金牌服务器只跑出龟速

近期协助出现场&#xff0c;解决了一个非常典型的UEFI 启动参数配置不当导致的服务器降效案例。错误的节能参数配置&#xff0c;导致价值几十万的服务器变成龟速服务器&#xff0c;并造成严重的生产事故。 1. 现象 朋友公司近期准备升级2010年就部署的服务器组&#xff0c;新…

《斯坦福数据挖掘教程·第三版》读书笔记(英文版) Chapter 2 MapReduce and the New Software Stack

来源&#xff1a;《斯坦福数据挖掘教程第三版》对应的公开英文书和PPT Chapter 2 MapReduce and the New Software Stack Computing cluster means large collections of commodity hardware, including conventional processors (“compute nodes”) connected by Ethernet …

centos8 mysql 主从复制

♥️作者:小刘在C站 ♥️个人主页:小刘主页 ♥️每天分享云计算网络运维课堂笔记,努力不一定有收获,但一定会有收获加油!一起努力,共赴美好人生! ♥️夕阳下,是最美的绽放,树高千尺,落叶归根人生不易,人间真情 目录 Linux centos8

使用D435i深度相机运行ORB-SLAM3

下载安装链接 下载ORB-SLAM3地址&#xff1a; git clone https://github.com/UZ-SLAMLab/ORB_SLAM3.git eigen3多版本安装&#xff1a;https://blog.csdn.net/weixin_41756645/article/details/129570141 ORB-SLAM2中eigen3版本为&#xff1a;3.2.10版本 ORB-SLAM3中eigen3版…

【分布式】一致性哈希和哈希槽

当我们拥有了多台存储服务器之后&#xff0c;现在有多个key&#xff0c;希望可以将这些个key均匀的缓存到这些服务器上&#xff0c;可以使用哪些方案呢&#xff1f; 1. 普通哈希取模法 1.1 直接哈希取模 这是一种最容易想到的方法&#xff0c;使用取模算法hash&#xff08;k…

AI绘图实战(七):室内设计线稿渲染、景观设计手绘稿改动、建筑照片转线稿|Stable Diffusion成为设计师生产力工具

S&#xff1a;AI能取代设计师么&#xff1f; I &#xff1a;至少在设计行业&#xff0c;目前AI扮演的主要角色还是超级工具&#xff0c;要顶替&#xff1f;除非甲方对设计效果无所畏惧~~ 预先学习&#xff1a; 安装及其问题解决参考&#xff1a;《Windows安装Stable Diffusion …