linux內核併發情景

通過《linux內核併發基本概念》,我們看到了,對於併發訪問共享資源,造成的運行結果與預期的不一致問題,這樣的結果是軟件設計者不能允許的。我們知道,我們編寫一個軟件一定是需要軟件實現特定的功能,如果我們在設計的時候,期望得到結果A,但實際軟件運行中卻得到的結果B,那麼這個軟件是相當糟糕的,因此,對於併發引起的競態,是我們在設計內核和驅動軟件時,必須要留意的。

在《linux內核併發基本概念》中,通過一個簡單的併發的場景,引出了競態、共享資源和臨界區等概念。接下來,本文就linux內核中,容易造成併發的場景,進行一下分析。我們學習知識,往往偏重於對問題的解決方法,而對需要解決什麼問題,一知半解,結果學完了方法,也不知道該怎麼去在實際中使用,所以andrew覺得,首先我們對需要解決的問題來進行分析,通過分析問題爲什麼會出現,出現後有什麼後果,來讓我們認識併發引起的競態到底是什麼,有心的讀者,可以在瞭解了問題之後,不要去翻閱資料查看linux併發控制,而是自己思考下如何解決這些問題,發散下自己的思維,也許會創造出比linux更好的併發控制方法呢。

本文只針對linux內核中常見的併發場景進行描述,爲了讓併發引起的競態問題展現的淋漓盡致,本文在場景中不使用任何併發控制。


圖1中,數組array爲全局的,函數ArrayWrite_A和函數ArrayWrite_B都可以訪問,執行函數ArrayWrite_A的線程爲線程A,執行函數ArrayWrite_B的線程爲線程B。

 

對稱多處理器:

       Linux內核從2.0版本開始支持對稱多處理器,對稱多處理器可以理解爲一個計算機中有多個CPU,多個CPU共享內存、總線等資源。對稱多處理器可以同時運行,每個CPU可以同時運行不同的代碼段,也可能同時運行同一代碼段。



如圖2所示,例如CPU1和CPU2上執行的兩個程序流,程序流1恰好運行好函數ArrayWrite_A開始處,同時,程序流2恰好運行到函數ArrayWrite_B的開始處,如果兩個CPU繼續運行下去,兩條數據流併發運行引起的競態,會對共享數組array造成什麼樣的影響,我們是無法預知的,但肯定不是我們想要的結果。




再來看一個簡單的例子,如圖3,data爲一個全局的整形變量,初值爲0,函數DataWrite將入參的值賦給全局變量data。在對稱多處理器中,多個CPU也可能同時運行同一個代碼段,如果CPU1和CPU2同時運行同一個代碼段,該代碼段包含圖3中的函數,那麼當兩個CPU執行完函數DataWrite的代碼後,全局變量的data的值到底是哪個CPU運行的結果呢?這就無法預知了。

 

中斷:

       中斷也是linux內核中主要的併發源,因爲中斷可能隨時會打斷正在運行的代碼,這就造成了競態的危險。




線程A會調用圖1中函數ArrayWrite_A,而中斷處理程序會調用函數ArrayWrite_B。如圖4所示,當線程A正在執行時,中斷產生打斷了線程A的執行,而中斷處理程序也需要對全局數據array進行操作,這樣就會引起全局數組array的數據不一致問題。如果線程A已經對全局數組array賦值完畢,中斷處理程序勢必會覆蓋線程A的賦值結果。如果線程A在中斷處理程序之後對全局數據array進行賦值,又勢必會覆蓋掉中斷處理程序的結果,如果線程A正在對全局數組array進行賦值,還沒有賦值完畢,而被中斷處理程序打斷,那麼全局數組array的賦值情況就是未知的。

 

除了中斷外,中斷下半部也是併發的主要來源,這部分會在中斷下半部中介紹。在linux內核2.6之後,開始支持內核搶佔,正在執行的內核代碼,隨時可能被搶佔,這又會導致併發,從而引起競態的可能。

 

Ok,通過對對稱多處理器和中斷引起的併發場景進行描述,希望讀者能更加深入地瞭解什麼是併發,以及併發引起的競態造成了什麼樣的後果。如果還沒有了解過linux內核併發控制的讀者,先不要去查看linux併發控制相關的資料,可以先想一下,上述的情景中,如何能夠解決競態引起的數據不一致問題呢?


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章