精品国产人成在线_亚洲高清无码在线观看_国产在线视频国产永久2021_国产AV综合第一页一个的一区免费影院黑人_最近中文字幕MV高清在线视频

0
  • 聊天消息
  • 系統消息
  • 評論與回復
登錄后你可以
  • 下載海量資料
  • 學習在線課程
  • 觀看技術視頻
  • 寫文章/發帖/加入社區
會員中心
創作中心

完善資料讓更多小伙伴認識你,還能領取20積分哦,立即完善>

3天內不再提示

函數的可重入與線程安全有什么關系

汽車電子技術 ? 來源:宅學部落 ? 作者: 王利濤 ? 2023-02-17 09:39 ? 次閱讀

嵌入式裸機時代,也就是無OS時代,我們在裸機環境下編寫C語言程序非常簡單,實現一個函數,然后將函數接口API提供給其它模塊調用就可以了。比如下面的函數,我們實現一個sum函數,用來求兩個數的和:

圖片

但是在一個運行OS的多任務環境中,我們在編寫sum函數時就要注意一些細節了:我們編寫的sum函數可能會被多個任務調用,而且可能在sum函數執行的過程被打斷,接著在另一個任務中再次調用sum函數。而在上面的sum函數實現中,我們定義了一個靜態變量sum用來保存兩個數相加的臨時結果,靜態變量是保存到數據段中的,大家可以想一想,在一個任務A中正在執行sum(1,2)函數中的第4行,此時任務被打斷掛起,接著運行任務B,在任務B中接著執行sum(10,20)函數,執行結束后接著運行任務A,A獲得CPU控制權后繼續運行sum(1,2)的第5行,此時sum(1,2)的返回結果就變成了30,而不是正確結果3。

在一個多任務環境中,如果一個函數可以重復并發調用,而且多次調用并不會影響函數的運行結果,那么這個函數是可重入的,我們稱這個函數為:可重入函數。在上面的sum函數實現中,當其被多次并發調用時,函數的運行結果并不確定,我們稱其為不可重入函數。

我們如何去判定一個函數是可重入的,還是不可重入的呢?很簡單,當一個函數滿足下面任一條件,那么這個函數就是不可重入函數。

  • 函數內部使用了全局變量
  • 函數內部使用了靜態局部變量
  • 函數返回值為全局變量或靜態變量
  • 函數內部使用了malloc/free函數
  • 函數北部使用了標準I/O函數
  • 函數內部調用其它不可重入函數

不可重入函數在一個多任務環境中不能被多次并發調用,如果一個函數可能被多次調用,那么我們設計這個函數時盡量要將其設計為可重入函數。

  • 不使用/返回靜態變量、全局變量
  • 不使用標準I/O函數
  • 不使用malloc/free函數
  • 不調用不可重入函數

在函數設計時,只要注意上面的原則,那么我們就可以將一個函數設計為可重入函數,可重入函數在多任務環境下可以被多次并發調用,是線程安全的,程序員可以放心大膽地調用。

理想很豐滿,現實很骨干。我們在編程中如果說不用malloc/free、全局變量,那是不現實的。只要我們使用了這些全局變量,靜態變量,那么函數就變成不可重入了,在多任務環境下使用這個函數就變得線程不安全了,那怎么辦呢?

方法還是有的,一個函數之所以變得不可重入,就是因為函數內有一些資源是全局共享的,在多任務環境下多次并發調用該函數時可能會破壞掉這些共享的全局資源。我們如果把這些資源在訪問的時候保護起來,不讓其它任務訪問(即互斥訪問),即同一時刻只允許一個進程訪問就安全了。這些被保護的資源我們稱為臨界資源,訪問這些臨界資源的代碼段,我們稱之為臨界區。臨界區的訪問方式為互斥訪問,即同一時刻只允許一個進程訪問。

臨界區的實現方式有很多種,不同的操作系統可能會提供不同的實現方式。我們可以通過下面的操作原語來實現一個臨界區:

  • EnterCriticalSection()
  • LeaveCriticalSection()

不同的操作系統,具體的實現手段可能不一樣,常見的方法有:關中斷;實現互斥訪問,比如通過信號量、互斥量、自旋鎖等實現,甚至原子操作等。比如在uc/os操作系統中,我們使用關中斷的方式來實現臨界區,確保函數的線程安全。

圖片

而在linux/windows操作系統中,我們通常使用鎖機制來實現臨界區:

圖片

在一個不可重入函數中,通過臨界區來實現共享全局資源的互斥訪問,那么在多任務環境下調用這個函數也就變得安全了,也就是說這個不可重入函數是線程安全的。

通過上面的分析,我們可以得出下面的結論:一個函數如果是可重入函數,那么這個函數是線程安全的,其它進程線程都可以對這個函數并發訪問,并不會影響函數的運行結果。如果一個函數是不可重入函數,我們通過臨界區設計對共享全局資源進行互斥訪問,也可以讓這個函數變得線程安全,其它進程線程也可以放心調用。由此,我們得出線程安全與可重入之間的關系如下:

圖片

也就是說,一個可重入函數肯定是線程安全的,而線程安全函數并不一定是可重入函數,不可重入函數也有可能是線程安全的,比如我們常見的malloc函數,就是不可重入函數,但是是線程安全的,為什么呢?

通過《C語言嵌入式Linux高級編程》課程學習,我們已經知道,對于我們使用malloc/free申請釋放的內存,glibc在用戶空間實現了一個內存管理器,將各個大小的內存塊鏈成多個全局鏈表進行管理。

圖片

當我們使用malloc/free申請釋放內存時,如果申請/釋放的內存塊大小符合規定,一般都是直接對這些全局鏈表進行操作、避免多次系統調用進入內核態,減少系統開銷。因為malloc/free函數對全局鏈表進行了操作,所以malloc/free是不可重入函數。在訪問這些全局鏈表時,我們需要通過鎖機制加以保護,每次malloc/free操作全局鏈表時,其它地方就被互斥訪問了,只有當malloc/free操作全局鏈表完成退出,其它地方的malloc/free才能對這個全局鏈表進行訪問。

通過上面的分析,我們可以看到:malloc/free雖然是不可重入函數,但是通過加鎖對共享全局資源的互斥訪問,也就變得線程安全了,在多任務環境下,每個進程都可以放心大膽地調用它:因為malloc雖然是不可重入函數,但它是線程安全的。

聲明:本文內容及配圖由入駐作者撰寫或者入駐合作網站授權轉載。文章觀點僅代表作者本人,不代表電子發燒友網立場。文章及其配圖僅供工程師學習之用,如有內容侵權或者其他違規問題,請聯系本站處理。 舉報投訴
  • 嵌入式
    +關注

    關注

    5068

    文章

    19017

    瀏覽量

    303262
  • C語言
    +關注

    關注

    180

    文章

    7598

    瀏覽量

    136191
  • 函數
    +關注

    關注

    3

    文章

    4306

    瀏覽量

    62430
收藏 人收藏

    評論

    相關推薦

    Keil C51處理科重入函數問題的探討

    在程序設計中,變量具體可以分為四種類型: 全局變量 ,靜態全局變量,局部變量,靜態局部變量。這幾種變量類型對函數重入產生的重大的影響,因為不同的編譯器采用不同的策略。 針對51的存儲區有
    發表于 04-22 21:40

    調用非安全線程的dll的問題

    在調用非線程安全的dll時,是不是要選擇在UI線程中運行?是不是還必須用不可重入的子VI封裝一下?上述的兩步是不是都要做?這些問題不是很清楚,還請各位大神指點一下
    發表于 03-14 21:13

    我想問如果我異步調用重入 參數是X80會怎么樣

    這個問題 因為我感覺里面有的地方很怪異,我在這些線程里用了全局變量 存了這個重入的VI的停止事件引用在別的地方去調用 停止它 就有時候 感覺并不能停止掉 關閉工程文件時候說是有線程
    發表于 06-06 19:38

    用ERTM關閉全局中斷來實現函數重入性有什么附加影響?

    在編程中,用ERTM關閉全局中斷來實現函數重入性有什么附加影響?
    發表于 08-09 11:12

    重入函數相關資料推薦

    數碼管點亮時間約為1~2ms。在數碼管數字變化時,先熄滅再更新數據,稱為消隱。using 0 是第0組寄存器;reentrant聲明的函數重入函數
    發表于 01-11 07:37

    函數對FFT有什么影響?他們是什么關系

    函數對FFT有什么影響?他們是什么關系?在visualStudio軟建中,要對音頻信號進行FFT變換時,需要加窗函數進行控制,這是為什么?窗函數對FFT有什么影響?窗
    發表于 11-30 06:24

    Linux 多線程重入函數

    的相互影響,如果一個函數在多線程并發的環境中每次被調用產生的結果是不確定的,我們就說這個函數是"不可重入的"/"線程
    發表于 05-16 17:41 ?928次閱讀

    重入函數與不可重入函數分析

    導致不可預料的后果。那么什么是重入函數呢?所謂重入函數是指一個可以被多個任務調用的過程,任務
    發表于 04-02 14:43 ?802次閱讀

    51單片機的重入函數有什么陷阱

    函數一旦定義為重入, 參數就會通過堆棧傳遞。 不要忘記的是, 局部變量也會在堆棧上分配。 更不能忽略的是, 51的堆棧空間大小是在2^8以內的, 所以堅決不能在
    發表于 08-20 17:31 ?0次下載
    51單片機的<b class='flag-5'>可</b><b class='flag-5'>重入</b><b class='flag-5'>函數</b>有什么陷阱

    重入和不可重入函數的詳細資料和應用簡介

    重入一般可以理解為一個函數在同時多次調用,例如操作系統在進程調度過程中,或者單片機、處理器等的中斷的時候會發生重入的現象。一般浮點運算都是由專門的硬件來完成,舉個例子假設有個硬件寄存器名字叫做FLOAT,用來計算和存放浮點數的中
    發表于 08-02 17:34 ?0次下載
    <b class='flag-5'>可</b><b class='flag-5'>重入</b>和不可<b class='flag-5'>重入</b><b class='flag-5'>函數</b>的詳細資料和應用簡介

    KEIL C51的重入函數的詳細資料講解

    重入函數,又叫再入函數,是一種可以在函數體內不直接或間接調用其自身的一種函數。再入函數可被遞歸調
    發表于 08-01 17:35 ?0次下載
    KEIL C51的<b class='flag-5'>重入</b><b class='flag-5'>函數</b>的詳細資料講解

    Linux中的重入、異步信號安全線程安全

    下文是在看csapp的時候引發的一些思考,其實之前看anup的時候也有所了解,不過時間有點長了,所以有點忘記了,當再次在csapp看到這部分內容的時候有了更多的理解。 重入函數 當一個被捕獲的信號
    的頭像 發表于 11-10 14:45 ?1318次閱讀
    Linux中的<b class='flag-5'>可</b><b class='flag-5'>重入</b>、異步信號<b class='flag-5'>安全</b>和<b class='flag-5'>線程</b><b class='flag-5'>安全</b>

    為什么中斷處理函數不能直接調用不可重入函數

    中斷丟失和系統位置錯誤,這里直接導致嵌入式 linux 系統應用進程中的所有線程停掉,進而導致看門狗進程得不到喂狗,設備重啟。 那什么是不可重入函數呢? 為什么中斷處理函數不能直接調用
    的頭像 發表于 02-17 09:33 ?5865次閱讀

    &quot;重入&quot;和&quot;線程安全&quot;是兩個概念 千萬不要搞混了

    ? ? 今天的這篇文章應該可以幫助你解決一大部分問題。 ? 01 兩個概念 1、重入函數?? 多任務系統中每個進程或線程都是由多種執行流并發運行的,當執行流同時進入同一個
    的頭像 發表于 02-10 17:38 ?3230次閱讀
    &quot;<b class='flag-5'>可</b><b class='flag-5'>重入</b>&quot;和&quot;<b class='flag-5'>線程</b><b class='flag-5'>安全</b>&quot;是兩個概念 千萬不要搞混了

    CPU的核心數和線程數有什么關系

    1 概念 1.1 背景 當看到以下一些名詞,你是否感到過疑惑:他們之間到底有什么關系? CPU核心數、線程數、處理器數量、每個處理器的內核數量、處理器內核總數、邏輯核數… 在安裝linux虛擬機
    的頭像 發表于 11-24 16:22 ?6075次閱讀
    CPU的核心數和<b class='flag-5'>線程</b>數有<b class='flag-5'>什么關系</b>