zoukankan      html  css  js  c++  java
  • 可重入和不可重入【转】

    转自: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后缀的同名可重入函数版本。如果实在没有,不妨在可预见的发生错误的地方尝试加上保护锁同步机制等等。

  • 相关阅读:
    leetcode 673. 最长递增子序列的个数 java
    leetcode 148. 排序链表 java
    leetcode 98. 验证二叉搜索树 java
    leetcode 29. 两数相除 java
    leetcode 234. 回文链表 java
    Valid Palindrome LeetCode Java
    Single Number II LeetCode Java
    Single Number LeetCode java
    Search in Rotated Sorted Array II LeetCode Java
    Search in Rotated Sorted Array leetcode java
  • 原文地址:https://www.cnblogs.com/sky-heaven/p/5341759.html
Copyright © 2011-2022 走看看