可重入函式 可重入核心

2021-05-02 23:15:36 字數 3386 閱讀 5935

可重入函式這一概念早有接觸,但一直未有系統的理解,最近閱讀《

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

dupgetsockopt

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

縱觀上表,我們可以看出,有不少系統呼叫函式並沒有出現,換言之也就是非可重入性函式。函式不可重入的原因主要如下:

函式使用了

static

靜態資料結構 如:

struct passwd *getpwuid(uid_t uid);

struct passwd *getpwnam(const char *name);

struct passwd *getpwent(void); 以上

3個函式都是返回乙個指向

passwd

結構的指標,而該

passwd

結構通常都是函式中

static

變數,其內容在每次呼叫以上函式時都會被重寫。因此,當程序主程式與訊號處理程式中均呼叫了以上函式時,衝突就產生了。

函式呼叫了

malloc

和free

函式,正如文章最開始所提到的;

函式為標準

i/o的庫函式,因為大多數的標準

i/o庫函式的實現都使用了

global

全域性資料結構;

因此,若要寫可重入性函式的做法通常是我們在函式中只修改區域性變數,而不改變全域性變數,或盡量不使用全域性變數、靜態static變數。

事實上,與可重入性函式(

reentrant function

)對應的還有可重入核心(

reentrant kernel

),其區別和聯絡在《深入理解

linux

核心》上有較詳細的講解。

可重入核心:所有unix核心都是可重入的(reentrant),這意味著幾個程序可以同時在核心態下執行,當然在單處理器系統上,只有乙個程序在真正的執行,但是許多程序可以在核心態下阻塞,或者等待cpu,或者等待一些i/o操作的完成。

提供可重入的一種方式是編寫函式,這些函式只能修改區域性變數,不能修改全域性資料結構,這樣的函式叫做可重入函式。

但是可重入核心不僅僅侷限於這樣的可重入函式(儘管一些實時核心正是如此實現的),核心可以包含非重入函式,並且利用鎖機制保證一次只有乙個程序執行乙個非重入函式。處於核心態的每個程序只能作用於自己的記憶體空間,不能干預其它的程序。

可重入核心 可重入函式

可重入核心在ulk 深入理解linux核心 中的定義是指若干個程序可以同時在核心態下執行,也就是說多個程序可以在核心態下併發執行核心 在單處理器上,只能實現 微觀上的序列,巨集觀上的並行,即任意時刻,只有乙個進 正執行,其他程序處於阻塞或者等待狀態。這裡的可重入,是指可以多個程序進入核心,並不是重複...

可重入核心

所有的unix核心都是可重入的,這意味著若干個程序可以同時在核心態下執行 提供可重入的一種方式是編寫函式,以編寫這些函式只能修改區域性變數,而不能修改全域性資料結構,這樣的函式叫可重入函式。但是可重入核心不僅僅侷限於這樣的可重入函式。相反,可重入核心可以包含非重入函式,並且利用鎖機制保證一次只有乙個...

可重入函式

在實時系統的設計中,經常會出現多個任務呼叫同乙個函式的情況。如果這個函式不幸被設計成為不可重入的函式的話,那麼不同任務呼叫這個函式時可能修改其他任務呼叫這個函式的資料,從而導致不可預料的後果。那麼什麼是可重入函式呢?所謂可重入函式是指乙個可以被多個任務呼叫的過程,任務在呼叫時不必擔心資料是否會出錯。...