(不)可重入函数

连接:https://baike.baidu.com/item/%E5%8F%AF%E9%87%8D%E5%85%A5%E5%87%BD%E6%95%B0/4521100?fr=aladdinhtml

          http://www.gnu.org/software/libc/manual/html_node/POSIX-Safety-Concepts.html#POSIX-Safety-Conceptsnode

  • 可重入函数

     在 实时系统的设计中,常常会出现多个任务调用同一个函数的状况。若是这个函数不幸被设计成为不可重入的函数的话,那么不一样任务调用这个函数时可能修改其余任 务调用这个函数的数据,从而致使不可预料的后果。那么什么是可重入函数呢?所谓可重入是指一个能够被多个任务调用的过程,任务在调用时没必要担忧数据是否会 出错。不可重入函数在实时系统设计中被视为不安全函数。安全

     知足下列条件的函数多数是不可重入的:数据结构

(1)函数体内使用了静态的数据结构;多线程

(2)函数体内调用了malloc()或者free()函数(malloc内部维护了全局的链表用来管理分配的内存,这就是状态信息,free也同样),并且malloc函数虽然自己是线程安全的,但系统调用时存在全局的heap lock(堆内存锁(全局锁),保证堆内存分配时的一致连续性),信号句柄中使用malloc函数时,有可能会发生在主程序调用malloc时,但还未结束,heap lock还未释放,被信号所中断,再次调用malloc函数,就会出现同一线程对heap lock连续两次锁,即会出现死锁 deadlock。);函数

(3)函数体内调用了标准I/O函数ui

  (4)进行了浮点运算.许多的处理器/编译器中,浮点通常都是不可重入的 (浮点运算大多使用协处理器或者软件模拟来实现。spa

  把一个不可重入函数变成可重入的惟一方法是用可重入规则来重写他。其实很简单,只要遵照了几条很容易理解的规则,那么写出来的函数就是可重入的。   操作系统

 (1)不要使用全局变量。由于别的代码极可能覆盖这些变量值。线程

 (2)在和硬件发生交互的时候,切记执行相似disinterrupt()之类的操做,就是关闭硬件中断。完成交互记得打开中断,在有些系列上,这叫作“进入/退出核心”或者用OS_ENTER_KERNAL/OS_EXIT_KERNAL来描述。//这是临界区保护

 (3)不能调用任何不可重入的函数。
  (4)谨慎使用堆栈。最好先在使用前先OS_ENTER_KERNAL。

  • 与线程安全的关系

可重入与 线程安全两个概念都关系到函数处理资源的方式。可是,他们有重大区别:
  • 可重入概念会影响函数的外部接口,而线程安全只关心函数的实现。
    • 大多数状况下,要将不可重入函数改成可重入的,须要修改函数接口,使得全部的数据都经过函数的调用者提供。
    • 要将非线程安全的函数改成线程安全的,则只须要修改函数的实现部分。通常经过加入 同步机制以保护共享的资源,使之不会被几个线程同时访问。
  • 操做系统背景与CPU调度策略:
    • 可重入是在单线程操做系统背景下,重入的函数或者子程序,按照后进先出的线性序依次执行完毕。
    • 多线程执行的函数或子程序,各个线程的执行时机是由操做系统调度,不可预期的,可是该函数的每一个执行线程都会不时的得到CPU的时间片,不断向前推动执行进度。
  • 可重入函数未必是线程安全的;线程安全函数未必是可重入的。
    • 例如,一个函数打开某个文件并读入数据。这个函数是可重入的,由于它的多个实例同时执行不会形成冲突;但它不是线程安全的,由于在它读入文件时可能有别的线程正在修改该文件,为了线程安全必须对文件加“同步锁”。
    • 另外一个例子,函数在它的函数体内部访问共享资源使用了加锁、解锁操做,因此它是线程安全的,可是却不可重入。由于若该函数一个实例运行到已经执行加锁但未执行解锁时被停下来,系统又启动该函数的另一个实例,则新的实例在加锁处将转入等待。若是该函数是一个中断处理服务,在中断处理时又发生新的中断将致使资源死锁。fprintf函数就是线程安全但不可重入。

 

  

可重入函数列表:

_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()。

相关文章
相关标签/搜索