目录

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.cgcc -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){//childwhile(true){cout<<"我是子进程:"<<getpid()<<endl;sleep(1);}exit(0);}//parentwhile(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系统上都可用。

(本篇完)

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

  1. Linux | 可重入函数 | volatile | SIGCHLD信号

    文章目录 可重入函数 可重入与线程安全 volatile volatile和const同时修饰变量 SIGCHLD信号 可重入函数 当一个函数可以被两个执行流调用,我们称该函数具有重入特征 如果一个函 ...

  2. Linux可重入函数

    1.可重入函数 可重入函数指的是可以被中断的函数.也就是说,可以在这个函数执行的任何时刻中断它,转入OS调度下去执行另外一段代码,而返回控制时不会出现什么错误:而不可重入的函数由于使用了一些系统资源, ...

  3. 【Linux学习】信号——信号保存 | 信号处理 | 不可重入函数,volatile,SIGCHLD信号

  4. Linux信号编程实践(二) 信号发送函数和可重入函数

    在早期的UNIX中信号是不可靠的,不可靠在这里指的是:信号可能丢失,一个信号发生了,但进程却可能一直不知道这一点. 现在Linux 在SIGRTMIN实时信号之前的都叫不可靠信号,这里的不可靠主要是不 ...

  5. linux操作系统之全局异步IO及可重入/不可重入函数

    (1)全局变量异步I/O实现父子进程交替数数 1)信号捕捉函数 2)main函数实现信号交替 3)程序实现 1>创建子进程,父进程等待1s,等待子进程完成捕捉函数注册(捕捉信号SIGUSR1). ...

  6. Linux进程信号(产生、保存、处理)/可重入函数概念/volatile理解/SIGCHLD信号

    首先区分一下Linux信号跟进程间通信中的信号量,它们的关系就犹如老婆跟老婆饼一样,没有一毛钱的关系. 信号的概念 信号的概念:信号是进程之间事件异步通知的一种方式,属于软中断.比如:红绿灯是一种信号 ...

  7. Linux系统编程34:进程信号之可重入函数,volatile关键字的作用和SIGHLD

    文章目录 (1)可重入函数 (2)volatile关键字 A:背景知识 B:产生的问题 C:volatile关键字 (3)SIGHLD信号 A:复习僵尸进程 B:清理僵尸状态的新方法-SIGCHLD ...

  8. UNIX再学习 -- 可重入函数和 SIGCHLD 语义

    一.可重入函数 参与信号处理的函数必须是可重入函数. 1.何为重入? 假设进程的住控制流程此刻正在调用 foo 函数,就在 foo 函数刚执行到一半的时候,内核向进程递送了信号 a:假设进程对信号 a ...

  9. Linux中的可重入函数和不可重入函数

    可重入函数 可重入函数(即可以被中断的函数)可以被一个以上的任务调用,而不担心数据破坏.可重入函数在任何时候都可以被中断,而一段时间之后又可以恢复运行,而相应的数据不会破坏或者丢失. 可重入函数使用的 ...

最新文章

  1. 初学者易上手的SSH-hibernate04 一对一 一对多 多对多
  2. python 编程一日一练-Python一日一练02----诗词生成器
  3. mp4文件时长 c++源码_【C语言】如何使用头文件 .h 编译 C 源码!so easy!
  4. HDU 2841 Visible Trees(容斥)题解
  5. Linux学习笔记 --组管理和权限管理
  6. 【FFMPEG】使用ffmpeg类库打开流媒体
  7. 【最短路】 ZOJ 1544 Currency Exchange 判断负圈
  8. mybatis字符串转成数字_JavaScript 字符串中的 pad 方法!
  9. php dcom扩展配置,PHP: 运行时配置 - Manual
  10. Devexpress ASP.NET最新版开发.NET环境配置Visual Studo和SQL Server对应版本
  11. Android Studio gradle 统一版本管理
  12. 留学Essay挂科后如何进行补救?
  13. 2个或2个以上路由器串联上网,在同一网段
  14. Mathematics English Vocabulary (Cited)
  15. 揽月摘星 | 第 13 届金鼠标数字营销大赛得奖名单出炉,知家斩获 5 项大奖
  16. 【Android】Binder的理解
  17. ZZULIOJ:1053: 正弦函数
  18. MSN 9.0 同时登陆多个账号
  19. ORB - (Oriented Fast and Rotated BRIEF)算法
  20. vc经验(它山之石)

热门文章

  1. 我是怎么薅的双十一羊毛
  2. chi2inv函数 matlab_matlab函数与指令大全 a——h (转载)
  3. 第二十二章 opengl之高级OpenGL(几何着色器)
  4. acrobat PDF删除部分_PDF原来可以这么玩
  5. 42、PCF8563电子时钟实验
  6. Google开放星空观测应用SkyMap源代码
  7. ArcGIS GeoEvent 使用教程(二)
  8. 《STM32学习笔记》4——核心功能电路与编程(下)
  9. 水果店开业活动,水果店开业活动策划
  10. Isito - Rate Limits(请求限速)