連接: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。
可重入函數列表:
_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()。