zoukankan      html  css  js  c++  java
  • (转载)可重入函数(reentrant function)

    (转载)http://blog.163.com/xu_jin_rong/blog/static/1491966220086775017178

    由于cublog系统的缘故,将前段时间写的一篇blog文章再次贴上。

    可重入函数这一概念早有接触,但一直未有系统的理解,最近阅读《APUE》信号一章时,其中讲解很到位,故总结如下。

    信号作为一种软中断,能够被进程给捕获,因而也就中断进程的正常执行,转而去执行信号处理程序,最后再返回到原进程继续正常执行。然而,当进程正在执行malloc()动态内存分配时,信号产生从而转入到信号处理程序,但当信号处理程序中也用到了malloc()函数时,问题就出来了?因为malloc()通常维护一个所有已分配内存链表,当信号发生时,进程可能正在修改链表指针,这时在信号处理程序中将又一次修改链表。当然类似的情况还有不少,下文中将会谈到。

    因此,在进行上层应用程序设计过程中我们就必须明确哪些函数是可重入性函数(reentrant functions)。可重入性函数通常也一定能够在信号处理程序(signal handler)中被调用。

    图1 能够在信号处理程序中调用的可重入性函数(节自《APUE》)

    accept

    fchmod

    lseek

    sendto

    stat

    access

    fchown

    lstat

    setgid

    symlink

    aio_error

    fcntl

    mkdir

    setpgid

    sysconf

    aio_return

    fdatasync

    mkfifo

    setsid

    tcdrain

    aio_suspend

    fork

    open

    setsockopt

    tcflow

    alarm

    fpathconf

    pathconf

    setuid

    tcflush

    bind

    fstat

    pause

    shutdown

    tcgetattr

    cfgetispeed

    fsync

    pipe

    sigaction

    tcgetpgrp

    cfgetospeed

    ftruncate

    poll

    sigaddset

    tcsendbreak

    cfsetispeed

    getegid

    posix_trace_event

    sigdelset

    tcsetattr

    cfsetospeed

    geteuid

    pselect

    sigemptyset

    tcsetpgrp

    chdir

    getgid

    raise

    sigfillset

    time

    chmod

    getgroups

    read

    sigismember

    timer_getoverrun

    chown

    getpeername

    readlink

    signal

    timer_gettime

    clock_gettime

    getpgrp

    recv

    sigpause

    timer_settime

    close

    getpid

    recvfrom

    sigpending

    times

    connect

    getppid

    recvmsg

    sigprocmask

    umask

    creat

    getsockname

    rename

    sigqueue

    uname

    dup

    getsockopt

    rmdir

    sigset

    unlink

    dup2

    getuid

    select

    sigsuspend

    utime

    execle

    kill

    sem_post

    sleep

    wait

    execve

    link

    send

    socket

    waitpid

    _Exit & _exit

    listen

    sendmsg

    socketpair

    write

    纵观上表,我们可以看出,有不少系统调用函数并没有出现,换言之也就是非可重入性函数。函数不可重入的原因主要如下:

    <!--[if !supportLists]-->(1)       <!--[endif]-->函数使用了static静态数据结构

    如:struct passwd *getpwuid(uid_t uid);

    struct passwd *getpwnam(const char *name);

    struct passwd *getpwent(void);

    以上3个函数都是返回一个指向passwd结构的指针,而该passwd结构通常都是函数中static变量,其内容在每次调用以上函数时都会被重写。因此,当进程主程序与信号处理程序中均调用了以上函数时,冲突就产生了。

    <!--[if !supportLists]-->(2)       <!--[endif]-->函数调用了malloc和free函数,正如文章最开始所提到的;

    <!--[if !supportLists]-->(3)       <!--[endif]-->函数为标准I/O的库函数,因为大多数的标准I/O库函数的实现都使用了global全局数据结构;

    因此,若要写可重入性函数的做法通常是我们在函数中只修改局部变量,而不改变全局变量,或尽量不使用全局变量、静态static变量。

    事实上,与可重入性函数(reentrant function)对应的还有可重入内核(reentrant kernel),其区别和联系在《深入理解Linux内核》上有较详细的讲解。

  • 相关阅读:
    单例模式
    关于static
    在O(1)时间复杂度删除链表节点
    奇偶分割数组
    用栈实现队列
    前序遍历和中序遍历树构造二叉树
    扇贝每日一句_1006
    寻找旋转排序数组中的最小值
    翻转链表
    扇贝每日一句_1002
  • 原文地址:https://www.cnblogs.com/Robotke1/p/3329607.html
Copyright © 2011-2022 走看看