可重入和不可重入【转】

转自:http://blog.csdn.net/wenhui_/article/details/6889013重入一般可以理解为一个函数在同时多次调用,例如操作系统在进程调度过程中,或者单片机、处理器等的中断的时候会发生重入的现象。
一般浮点运算都是由专门的硬件来完成,举个例子假设有个硬件寄存器名字叫做FLOAT,用来计算和存放浮点数的中间运算结果
假设有这么个函数
void fun()
{
//...这个函数对FLOAT寄存器进行操作
}
假如第一次执行,有个对浮点数操作运算的结果临时存在FLOAT寄存器中,而就在这时被中断了,而中断函数或者另一个进程也调用fun函数,这时第二次调用的fun函数在执行的过程中就会破坏第一次FLOAT寄存器中的结果,这样当返回到第一次fun函数的时候,结果就不正确了。

可以把fun函数理解为printf()函数。

赞同

(转)可重入和不可重入

2011-10-04 21:38

这种情况出现在多任务系统当中,在任务执行期间捕捉到信号并对其进行处理时,进程正在执行的指令序列就被信号处理程序临时中断。如果从信号处理程序返回,则继续执行进程断点处的正常指令序列,从重新恢复到断点重新执行的过程中,函数所依赖的环境没有发生改变,就说这个函数是可重入的,反之就是不可重入的。
众所周知,在进程中断期间,系统会保存和恢复进程的上下文,然而恢复的上下文仅限于返回地址,cpu寄存器等之类的少量上下文,而函数内部使用的诸如全局或静态变量,buffer等并不在保护之列,所以如果这些值在函数被中断期间发生了改变,那么当函数回到断点继续执行时,其结果就不可预料了。打个比方,比如malloc,将如一个进程此时正在执行malloc分配堆空间,此时程序捕捉到信号发生中断,执行信号处理程序中恰好也有一个malloc,这样就会对进程的环境造成破坏,因为malloc通常为它所分配的存储区维护一个链接表,插入执行信号处理函数时,进程可能正在对这张表进行操作,而信号处理函数的调用刚好覆盖了进程的操作,造成错误。

满足下面条件之一的多数是不可重入函数:
(1)使用了静态数据结构;
(2)调用了malloc或free;
(3)调用了标准I/O函数;标准io库很多实现都以不可重入的方式使用全局数据结构。
(4)进行了浮点运算.许多的处理器/编译器中,浮点一般都是不可重入的 (浮点运算大多使用协处理器或者软件模拟来实现。

1) 信号处理程序A内外都调用了同一个不可重入函数B;B在执行期间被信号打断,进入A (A中调用了B),完事之后返回B被中断点继续执行,这时B函数的环境可能改变,其结果就不可预料了。
2) 多线程共享进程内部的资源,如果两个线程A,B调用同一个不可重入函数F,A线程进入F后,线程调度,切换到B,B也执行了F,那么当再次切换到线程A时,其调用F的结果也是不可预料的。
在信号处理程序中即使调用可重入函数也有问题要注意。作为一个通用的规则,当在信号处理程序中调用可重入函数时,应当在其前保存errno,并在其后恢复errno。(因为每个线程只有一个errno变量,信号处理函数可能会修改其值,要了解经常被捕捉到的信号是SIGCHLD,其信号处理程序通常要调用一种wait函数,而各种wait函数都能改变errno。)

可重入函数列表:

_exit()、 access()、alarm()、cfgetispeed()、cfgetospeed()、cfsetispeed()、cfsetospeed ()、chdir()、chmod()、chown()、close()、creat()、dup()、dup2()、execle()、 execve()、fcntl()、fork()、fpathconf ()、fstat()、fsync()、getegid()、 geteuid()、getgid()、getgroups()、getpgrp()、getpid()、getppid()、getuid()、 kill()、link()、lseek()、mkdir()、mkfifo()、 open()、pathconf()、pause()、pipe()、raise()、read()、rename()、rmdir()、setgid ()、setpgid()、setsid()、setuid()、 sigaction()、sigaddset()、sigdelset()、sigemptyset()、sigfillset()、 sigismember()、signal()、sigpending()、sigprocmask()、sigsuspend()、sleep()、 stat()、sysconf()、tcdrain()、tcflow()、tcflush()、tcgetattr()、tcgetpgrp()、 tcsendbreak()、tcsetattr()、tcsetpgrp()、time()、times()、 umask()、uname()、unlink()、utime()、wait()、waitpid()、write()。

书上关于信号处理程序中调用不可重入函数的例子:

#include <stdlib.h>
#include <stdio.h>
#include <pwd.h>

static void func(int signo)
{
    struct passwd *rootptr;
    if( ( rootptr = getpwnam( "root" ) ) == NULL )
    {
        err_sys( "getpwnam error" );
    }
    signal(SIGALRM,func);
    alarm(1);
}

int main(int argc, char** argv)
{
    signal(SIGALRM,func);
    alarm(1);
    for(;;)
    {
        if( ( ptr = getpwnam("sar") ) == NULL )
        {
            err_sys( "getpwnam error" );
        }
    }
    return 0;
}

signal了一个SIGALRM,而后设置一个定时器,在for函数运行期间的某个时刻,也许就是在getpwnam函数运行期间,相应信号发生中断,进入信号处理函数func,在运行func期间又收到alarm发出的信号,getpwnam可能再次中断,这样就很容易发生不可预料的问题。

 

=================================================================================

不可重入函数不可以在它还没有返回就再次被调用。例如printf,malloc,free等都是不可重入函数。因为中断可能在任何时候发生,例如在printf执行过程中,因此不能在中断处理函数里调用printf,否则printf将会被重入。 

函数不可重入大多数是因为在函数中引用了全局变量。例如,printf会引用全局变量stdout,malloc,free会引用全局的内存分配表。

个人理解:如果中断发生的时候,当运行到printf的时候,假设发生了中断嵌套,而此时stdout资源被占用,所以第二个中断printf等待第一个中断的stdout资源释放,第一个中断等待第二个中断返回,造成了死锁,不知这样理解对不对。

 

 

不可重入函数指的是该函数在被调用还没有结束以前,再次被调用可能会产生错误。可重入函数不存在这样的问题。
不可重入函数在实现时候通常使用了全局的资源,在多线程的环境下,如果没有很好的处理数据保护和互斥访问,就会发生错误。
常见的不可重入函数有:
printf --------引用全局变量stdout
malloc --------全局内存分配表
free    --------全局内存分配表
在unix里面通常都有加上_r后缀的同名可重入函数版本。如果实在没有,不妨在可预见的发生错误的地方尝试加上保护锁同步机制等等。

时间: 2024-11-08 20:16:53

可重入和不可重入【转】的相关文章

顺序栈入栈时输入入栈元素回车之后不能够运行,需要再输入个字节才能运行。预计主函数存在问题。

问题描述 顺序栈入栈时输入入栈元素回车之后不能够运行,需要再输入个字节才能运行.预计主函数存在问题. #include #include #define MAXSIZE 100 //顺序栈的存储空间的初始分配量 #define SElemType int typedef struct { SElemType *base; SElemType *top; int stacksize; } SqStack; //栈的初始化 void InitStack(SqStack *S) { S->base=(

简易聊天程序中,C/S架构中C端通过能实现断开重连,为什么重连后不能接受服务端的对象。

问题描述 C/S描述:C端发送文本对象到S端,S端接受文本对象,并负责将文本对象发送到每个C端并显示.问题:现在通过try/catch捕获socket连接异常后,用调用原来的连接实现重连后,S端能接收到C端的对象且能将文本发送到C端.但是C端的接收消息的线程好像不能被重新打开,即C端不能接收S端的对象了.C/S架构中C端通过能实现断开重连,为什么重连后不能接受服务端的对象.importjava.awt.*;importjava.awt.event.*;importjava.io.*;import

游艺春秋张新敬:页游重研发 端游重运营

游艺春秋张新敬:页游重研发 端游重运营 近日,游艺春秋发布动作回合页游<阴阳冕>,预计月内上线.游艺春秋副总裁张新敬在接受DoNews游戏频道记者采访时表示,新款页游发布不会影响端游业务,游艺春秋在端游领域扮演运营角色,而在页游领域则注重研发. 51wan高楠楠:建立安全中心 保护玩家利益 "3.15"临近,DoNews游戏频道就页游外挂和玩家投诉等问题采访了51wan助理总裁高楠楠女士.她表示,51wan打击外挂的决心非常坚决,公司在二季度推出安全中心来保护玩家利益,打造

智慧城市投资或超万亿 重形式更要重内涵

"全国已有95%的副省级以上城市,76%以上的地级市,超过250多个城市提出发展智慧城市,并出台了相应规划,计划投资规模超过万亿元,智慧城市建设已成地方政府的狂欢."近日,在中博会物联网应用暨智慧城市论坛上,国资委机械工业经济管理研究院副研究员吕汉阳表示,目前大多数城市对智慧城市建设仍缺乏明确定位和目标,对如何开展存在困惑. "实际上,部分地方政府官员并不理解智慧城市内涵,重形式.轻实效,以为花钱买一大堆先进设备,就智慧了."吕汉阳认为,智慧城市的内涵,是通过数字化

三星S5怎么刷入recovery? S5 刷入recovery方法

1:我们把手机关机,(在此使用传统方法来进入S5 recovery) 2:接着我们在手机关机状态同时按下音量增加键 + Home键 + 电源键 然后我们一直等待就会显示进入到了一个命令界面了,进入之后我们就可以通过音量键来操作了. 3:进入recovery模式之后进行双清,不管你的手机是系统自带的recovery还是第三方的recovery,不管你是中方版的还是英文版的,只要有[wipe data/factory reset][清空数据/恢复出厂设置]和[wipe cache partition

重拾童年 Konami重制版魂斗罗热血归来

&http://www.aliyun.com/zixun/aggregation/37954.html">nbsp;   [ 科技讯]12月4日消息,当电脑尚未普及的80年代末,90年代初,红白机小霸王可以说是占据着每个孩子的大部分童年时光.虽然画面粗糙,玩法单一, 不过很多经典的游戏成为了那一代人难以割舍的情怀.       魂斗罗作为经典的射击类游戏中的代表作,已经成为了男孩子 心中无法取代的两名英雄.调30条命的 秘籍相信很 多人还能清晰的记得吧.为了向经典致敬,Konami

Facebook最新社交媒体报告:男性重实用,女性重个性

每一个平台都是独一无二的,这是每个媒体分析师和营销人员从一开始就要非常清楚的.在微博上火爆的内容不一定适合微信,而你在Facebook上发布的内容则又和Instagram上的完全不同. 而社交媒体更加强调差异化定位,就拿Google+来说,它在社交媒体的探索之所以失败了,是因为它试图按照Facebook的样子复制一个社交平台,这样的做法对于用户来说没有任何吸引力.社交平台必须首先具有差异性的功能才能获得用户的注意,继而加入这个平台. 既然如此,对于企业来说,摸清每一种社交平台的"脾气"

奚国华:域名注册重数量更要重质量

王兵 本报讯 (记者 王兵) 昨天,由中国互联网络信息中心(CNNIC)主办的中国首届域名大会在北京召开.工业和信息化部副部长奚国华在大会上指出,中国互联网作为全球互联网的重要组成部分,网络规模和用户规模持续迅速扩张,不仅有力地支持了国民经济和社会的发展,而且为全球互联网发展作出重要贡献.特别是去年以来,尽管国际金融危机蔓延,但我国互联网产业仍然保持较好的发展速度.互联网用户普及率目前已经达到23.9%,超过23.6%的世界平均水平.域名是互联网上的核心资源,我们不仅要提高域名注册数量,更要提高

2010亚冠签位:亚泰入连环套BIG4皆入死亡之组

2010年亚洲冠军联赛分组抽签仪式将在吉隆坡亚足联总部进行,结果代表中国出赛的前景都不容乐观.国安和鲁能都遭遇到了日韩澳三强围剿,亚泰的分组情况相对好点,是四支参赛队最有希望的一队,至于新军河南建业碰上如狼似虎的大阪钢巴和水原三星几乎没有出线的希望. 2010年亚洲冠军联赛分组抽签仪式将在吉隆坡亚足联总部进行,结果代表中国出赛的前景都不容乐观.国安和鲁能都遭遇到了日韩澳三强围剿,亚泰虽然同组三个对手都是联赛冠军,但是有可能出现连环套的局面,反而有可能在混沌的局面中逃出生天.至于新军河南建业碰上如