可重入函式和執行緒安全

2021-10-07 16:48:54 字數 2419 閱讀 4283

可重入函式和執行緒安全

可重入函式主要用於多工環境中,乙個可重入的函式簡單來說就是可以被中斷的函式,也就是說,可以在這個函式執行的任何時刻中斷它,轉入os排程下去執行另外一段**,而返回控制時不會出現什麼錯誤;而不可重入的函式由於使用了一些系統資源,比如全域性變數區,中斷向量表等,所以它如果被中斷的話,可能會出現問題,這類函式是不能執行在多工環境下的。

可重入函式也可以這樣理解,重入即表示重複進入,首先它意味著這個函式可以被中斷,其次意味著它除了使用自己棧上的變數以外不依賴於任何環境(包括static),這樣的函式就是purecode(純**)可重入,可以允許有多個該函式的副本在執行,由於它們使用的是分離的棧,所以不會互相干擾。如果確實需要訪問全域性變數(包括static),一定要注意實施互斥手段。可重入函式在並行執行環境中非常重要,但是一般要為訪問全域性變數付出一些效能代價。

編寫可重入函式時,若使用全域性變數,則應通過關中斷、訊號量(即p、v操作)等手段對其加以保護。若對所使用的全域性變數不加以保護,則此函式就不具有可重入性,即當多個執行緒呼叫此函式時,很有可能使有關全域性變數變為不可知狀態。

假設exam是int型全域性變數,函式square_exam返回exam平方值。那麼如下函式不具有可重入性。

unsigned int example(int para)

此函式若被多個程序呼叫的話,其結果可能是未知的,因為當(**)語句剛執行完後,另外乙個使用本函式的程序可能正好被啟用,那麼當新啟用的程序執行到此函式時,將使exam賦予另乙個不同的para值,所以當控制重新回到「temp = square_exam( )」後,計算出的temp很可能不是預想中的結果。此函式應如下改進。

unsigned int example( int para )

若申請不到「訊號量」,說明另外的程序正處於給exam賦值並計算其平方過程中(即正在使用此訊號),本程序必須等待其釋放訊號後,才可繼續執行。若申請到訊號,則可繼續執行,但其它程序必須等待本程序釋放訊號量後,才能再使用本訊號。

保證函式的可重入性的方法:在寫函式時候盡量使用區域性變數(例如暫存器、堆疊中的變數),對於要使用的全域性變數要加以保護(如採取關中斷、訊號量等方法),這樣構成的函式就一定是乙個可重入的函式。

vxworks中採取的可重入的技術有:

與執行緒的安全關係:

可重入與執行緒安全兩個概念都關係到函式處理資源的方式。但是,他們有重大區別:

可重入概念會影響函式的外部介面,而執行緒安全只關心函式的實現。大多數情況下,要將不可重入函式改為可重入的,需要修改函式介面,使得所有的資料都通過函式的呼叫者提供。

要將非執行緒安全的函式改為執行緒安全的,則只需要修改函式的實現部分。一般通過加入同步機制以保護共享的資源,使之不會被幾個執行緒同時訪問。

作業系統背景與cpu排程策略:

可重入是在單執行緒作業系統背景下,重入的函式或者子程式,按照後進先出的線性序依次執行完畢。多執行緒執行的函式或子程式,各個執行緒的執行時機是由作業系統排程,不可預期的,但是該函式的每個執行執行緒都會不時的獲得cpu的時間片,不斷向前推進執行進度。

可重入函式未必是執行緒安全的;執行緒安全函式未必是可重入的。

例如,乙個函式開啟某個檔案並讀入資料。這個函式是可重入的,因為它的多個例項同時執行不會造成衝突;但它不是執行緒安全的,因為在它讀入檔案時可能有別的執行緒正在修改該檔案,為了執行緒安全必須對檔案加「同步鎖」。

另乙個例子,函式在它的函式體內部訪問共享資源使用了加鎖、解鎖操作,所以它是執行緒安全的,但是卻不可重入。因為若該函式乙個例項執行到已經執行加鎖但未執行解鎖時被停下來,系統又啟動該函式的另外乙個例項,則新的例項在加鎖處將轉入等待。如果該函式是乙個中斷處理服務,在中斷處理時又發生新的中斷將導致資源死鎖。fprintf函式就是執行緒安全但不可重入。

不可重入函式:

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

滿足下列條件的函式多數是不可重入的:

函式體內使用了靜態的資料結構;

函式體內呼叫了malloc()或者free()函式;

函式體內呼叫了標準i/o函式。

下面舉例加以說明。

a. 可重入函式

void strcpy(char *lpszdest, char *lpszsrc)
b. 不可重入函式1

char ctemp;//全域性變數

void swapchar1(char *lpcx, char *lpcy)

c. 不可重入函式2

void swapchar2(char *lpcx,char *lpcy)

執行緒安全和可重入函式

執行緒安全 當多個併發執行緒執行同乙個函式,我們都能得到正確的返回值。當多個執行緒併發的呼叫乙個函式。如果對全域性資料或者靜態資料在不加任何鎖以及安全性的處理情況下,就會對多次修改資料的錯誤。比如我正在願意個執行緒裡處理乙個全域性變數的 1 正減完。結果還沒有返回,就被另乙個執行緒切出去了,而那個執...

執行緒安全和可重入函式

執行緒安全 乙個函式稱為執行緒安全,當且僅當被多個併發執行緒反覆呼叫時,它一直產生正確的結果。如果乙個函式不是執行緒安全的,我們就說它是執行緒不安全的。以下我們定義4種,執行緒不安全的函式 第1類 不保護共享變數的函式,比如對乙個全域性變數多個執行緒操作,產生錯誤結果 解決方法 利用像p,v操作這樣...

執行緒安全和可重入函式

簡單來說,在執行環境一致的情況下,多次執行同乙個多執行緒程式時,所有執行緒結果和單執行緒執行得到的結果一致時,則可以說該程式的執行緒是安全的。反之,則為執行緒不安全。引起執行緒安全問題的原因 通常都是由全域性變數及靜態變數的。若每個執行緒中對全域性變數 靜態變數只有讀操作,而無寫操作,一般來說,這個...