一、概述

怎么会有可重入和不可重入

在多任务系统下,中断可能在任务执行的任何时间发生;如果一个函数的执行期间被中断后,到重新恢复到断点进行执行的过程中,函数所依赖的环境没有发生改变,那么这个函数就是可重入的,否则就不可重入

在中断前后不都要保存和恢复上下文吗,怎么会出现函数所依赖的环境发生改变了呢?

我们知道中断时确实保存一些上下文,但是仅限于返回地址,cpu寄存器等之类的少量上下文,而函数内部使用的诸如全局或静态变量,buffer等并不在保护之列,所以如果这些值在函数被中断期间发生了改变,那么当函数回到断点继续执行时,其结果就不可预料了。

满足下面条件之一的多数是不可重入函数:

(1)使用了静态数据结构;

(2)调用了malloc或free;

(3)调用了标准I/O函数;

(4)进行了浮点运算.

malloc/free是不可重入的,它们使用了全局变量来指向空闲区;

标准I/O库的很多实现都使用了全局数据结构;

许多的处理器/编译器中,不可重入的 (浮点运算大多使用协处理器或者软件模拟来实现)。

在信号处理程序及多线程编程时,要特别注意。

考虑这种情况

1) 信号处理程序A内外都调用了同一个不可重入函数B;B在执行期间被信号打断,进入A (A中调用了B),完事之后返回B被中断点继续执行,这时B函数的环境可能改变,其结果就不可预料了。

2) 多线程共享进程内部的资源,如果两个线程A,B调用同一个不可重入函数F,A线程进入F后,线程调度,切换到B,B也执行了F,那么当再次切换到线程A时,其调用F的结果也是不可预料的。

在信号处理程序中即使调用可重入函数也有问题要注意。作为一个通用的规则,当在信号处理程序中调用可重

入函数时,应当在其前保存errno,并在其后恢复errno。(要了解经常被捕捉到的信号是SIGCHLD,其信号处理程序通常要调用一种wait函数,而各种wait函数都能改变errno。)

二、实例

给出一段程序,这段程序从信号处理程序my_alarm调用非可重入函数getpwnam,而my_alarm每秒被调用一次。在该程序中调用alarm函数使得每秒产生一次SIGALRM信号。

#include <stdio.h>
#include <pwd.h>
#include <unistd.h>
#include <string.h>
#include <signal.h> static void my_alarm(int signo){
struct passwd * rootptr; printf("in signal handler\n");
if((rootptr = getpwnam("root")) == NULL){
fprintf(stderr, "getpwnam(root) error\n");
}
alarm();
} int main(void){
struct passwd *ptr; signal(SIGALRM, my_alarm);
alarm();
for(;;){
if((ptr = getpwnam("ives")) == NULL){
fprintf(stderr, "getpwnam(ives) error\n");
}
if(strcmp(ptr->pw_name, "ives") != ){
printf("return value corrupted!, pw_name = %s\n", ptr->pw_name);
}
}
}

在大多数系统下,该代码不会正常工作,只会输出一串"in signal handler"就阻塞在那里不再运行。

[Linux]不可重入函数的更多相关文章

  1. linux: 可重入函数与不可重入函数

    1. 可重入函数与线程安全 摘自 多线程和多进程的区别(小结) http://blog.csdn.net/hairetz/article/details/4281931 要确保函数线程安全,主要需要考 ...

  2. Linux可重入函数和线程安全的区别与联系(转)

    *****可重入函数 函数被不同的控制流程调用,有可能在第一次调用还没返回时就再次进入该函数,这称为重入. 当程序运行到某一个函数的时候,可能因为硬件中断或者异常而使得在用户正在执行的代码暂时终端转而 ...

  3. linux系统编程之信号(四):alarm和可重入函数

    一,alarm() 在将可重入函数之前我们先来了解下alarm()函数使用: #include <unistd.h> unsigned int alarm(unsigned int sec ...

  4. 【Linux】可重入函数和线程安全的区别与联系【转】

    转自:http://blog.csdn.net/scenlyf/article/details/52074444 版权声明:本文为博主原创文章,未经博主允许不得转载. *****可重入函数 函数被不同 ...

  5. (转载)可重入函数(reentrant function)

    (转载)http://blog.163.com/xu_jin_rong/blog/static/1491966220086775017178 由于cublog系统的缘故,将前段时间写的一篇blog文章 ...

  6. linux可重入、异步信号安全和线程安全

    一 可重入函数 当一个被捕获的信号被一个进程处理时,进程执行的普通的指令序列会被一个信号处理器暂时地中断.它首先执行该信号处理程序中的指令.如果从信号处理程序返回(例如没有调用exit或longjmp ...

  7. Linux 可重入内核

    Linux内核是可重入的,这意味着几个进程可能同时在内核模式下执行.(当然单处理器系统,在某一时间只会有一个进程执行,但许多会阻塞在内核模式)这些进程会分时共享CPU.I/O设备等系统资源,给用户的感 ...

  8. Use Reentrant Functions for Safer Signal Handling(译:使用可重入函数进行更安全的信号处理)

    Use Reentrant Functions for Safer Signal Handling 使用可重入函数进行更安全的信号处理 How and when to employ reentranc ...

  9. 可重入函数、线程安全、volatile

    一. POSIX 中对可重入和线程安全这两个概念的定义: Reentrant Function:A function whose effect, when called by two or more  ...

随机推荐

  1. java数组2

    package lastt; public class last { String name;int age; public last(String name,int age) { this.name ...

  2. Spring Boot报错 MultipartException The temporary upload...

    Spring Boot报错:尤其是在处理Ribbon这类接口调用型的负载均衡组件,常见问题 ERROR o.a.c.c.C.[.[.[.[dispatcherServlet] - Servlet.se ...

  3. Day 1 下午

    POINT 1 贪心 每一步都取当前的最优解的思想:一般来说符合直观思路,需要严格的证明:OI中使用多个错误的贪心策略进行加成有时会有良好的效果 例一给定N个农民,第i个农民有Ai单位的牛奶,单价Pi ...

  4. logstash filter 处理json

    根据输入的json字段,分别建立索引.循环生成注册log和登录log保存到testlog文件中,结果如下: {"method":"register"," ...

  5. webstorm开发微信小程序

    参考博客:https://www.cnblogs.com/pansidong/articles/7563155.html

  6. thinkphp5: 循环输出表格,并固定表格单元宽度(过长省略号)

    html: <table class="table table-striped" style='table-layout:fixed;'> <thead clas ...

  7. RSA加密传输代码示例

    RSA加密传输代码示例 涉及敏感数据的传输,双方最好约定使用加密解密.那RSA非对称加密就大有作为了.服务端可以保留自己的私钥,发给客户端对应的公钥.这样就可以互相加解密了.php中rsa加解密实现: ...

  8. Node.js目录

    [相关学习] npm入门教程 [基础] (1) 初识Node.js (2) 开发环境和调试工具 (3) commonJs 规范 (4) node 概念(global.process进程.调试) (5) ...

  9. lillietest 正态分布的拟合优度测试

    函数 lillietest格式 H = lillietest(X) %对输入向量X进行Lilliefors测试,显著性水平为0.05.H = lillietest(X,alpha) %在水平alpha ...

  10. vue生命周期的理解

    我从官网上下载了一张vue生命周期的图,接下来实际分析一波vue到底执行了什么东西. 1.我们在使用vue时必不可少的操作就是 var vm = new Vue({}),这样我们就创建了一个vue的实 ...