Linux中的併發和競態

2021-06-04 06:11:24 字數 2010 閱讀 6506

本帖大體上描述linux kernel為解決併發導致的競態所提供的核心api(主要是訊號量和自旋鎖)之間的區別,側重於使用方面。**級的閱讀比較打算另開一貼。

因為程式的併發執行而導致的競態是linux核心中乙個非常複雜的方面。對於裝置的驅動程式開發者而言,熟悉linux核心提供的併發互斥的處理機制相當重要。所謂競態,簡而言之,是多個核心執行緒有可能對同一資源進行操作時可能導致的核心資料紊亂的行為。共享資料是併發的根本原因。

併發的**—

我把併發**分為兩個大的方面來分別進行討論:單處理器和多處理器。

1.單處理器

對於單處理器而言,併發主要來自於中斷,可搶占的核心和各種延遲佇列。

2.多處理器

多處理器的情況更加複雜,在同一時間,同一**可同時在不同處理器上執行。對這種併發的處理要更加棘手。

核心的互斥設施—

驅動程式開發者對核心提供的互斥機制的確切理解是寫出高安全性**的關鍵。在linux核心中,這種設施主要是訊號量和自旋鎖。

1.訊號量

訊號量的原理主要是基於對一記憶體單元的原子性的測試和設定操作(atomic test and set),不同處理器有不同的組合語言用於提供這種機制。因為記憶體單元對於多處理器系統中的每個處理器都是共享的,所以這種機制同樣適用於多處理器。

相對於自選鎖,訊號量的最大特點是允許呼叫它的執行緒進入睡眠狀態。這意味著試圖獲得某一訊號量的執行緒會導致對處理器擁有權的喪失,也即出現程序的切換。

2.自旋鎖

自旋鎖的出現最初是為了解決多處理器上出現的互斥問題。其原理是,試圖獲得鎖的執行緒去進行原子性的位測試和設定操作(atomic bit test and set),如果沒有別的處理器進入臨界區,那麼當前執行緒將獲得鎖,鎖定之後進入臨界區。如果有別的處理器在臨界區中,那麼當預處理器將進入忙等待狀態,直到其他處理器解開該鎖。與訊號量最大的區別是,試圖進入臨界區的執行緒如果得不到鎖,那麼就一直不停地執行atomic bit test操作而不會進入睡眠狀態。這種情況下,試圖獲得鎖的處理器上將啥工作也幹不了(除了進行這種atomic bit test操作外),正因為如此,所以要求獲得鎖的執行緒要以最短的時間結束臨界區中的操作。

在單處理器上,自旋鎖更確切的意義是,乙個試圖獲得鎖的執行緒實際上是向系統通告:當我執行下面**時,不要將我切換出處理器。因此,單處理器上的自旋鎖**實際是在完成對處理器的強制擁有的操作。而在單處理器上,中斷和搶占是最大可能的併發源頭,所以,實際上單處理器上的自旋鎖的實現**簡單歸結為:關中斷和關閉搶占。理解spin lock的實現**需要深刻的處理器相關知識和組合語言。

基於以上的實現原理,使用自旋鎖的乙個核心規則是:擁有鎖的執行緒絕對不可以放棄處理器。因為假設它放棄了處理器,那麼另乙個獲得處理器執行緒的**如果想獲得該鎖,將不得不等待很長的時間,更壞的情況下導致系統的死鎖。更具體的描述:在單處理器上,乙個獲得鎖的執行緒必然執行在中斷和搶占都關閉的環境中,這種情況下被動的放棄處理器已經成為不可能,只有主動放棄處理器才會出現,比如在互斥**中呼叫了copy_from_user,該函式的實現中使程序進入休眠成為可能,如果恰巧下乙個被排程執行的執行緒試圖獲得該鎖,那麼系統將進入死鎖狀態,因為這種情況下後來被排程的執行緒已經沒有主動放棄處理器的可能(因為它此時正執行試圖獲得鎖的**,不可能呼叫到那些有可能主動放棄處理器的函式)。具體的例子:

假設系統中有a和b兩個執行緒,當a執行緒執行到下面的**時將可能會丟失處理器:

spinlock_t   g_lock = spin_lock_unlocked;  //乙個全域性的spin_lock 變數

a**:

spin_lock_init(&g_lock);

spin_lock (&g_lock);

copy_from_user(…);  //a執行緒在該函式中失去處理器的擁有權

被排程執行的b執行緒**:

…spin_lock (&g_lock); //因為已經休眠的a執行緒沒有釋放g_lock,所以b執行緒將永遠在此處自旋下去。注意此時中斷和搶占都是關閉的,即被動放棄處理器已經不可能。

互斥問題的複雜性恰恰就在這裡:休眠可發生在許多無法預期的地方。因此當我們編寫需要在自旋鎖下執行的**時,必須注意每乙個所呼叫的函式

Linux中的併發和競態

本帖大體上描述linux kernel為解決併發導致的競態所提供的核心api 主要是訊號量和自旋鎖 之間的區別,側重於使用方面。級的閱讀比較打算另開一貼。因為程式的併發執行而導致的競態是linux核心中乙個非常複雜的方面。對於裝置的驅動程式開發者而言,熟悉linux核心提供的併發互斥的處理機制相當重...

LDD 併發和競態

1.正在執行的多個使用者空間程序可能以一種令人驚訝的組合方式訪問我們的 2.smp系統甚至可在不同的處理器上同時執行我們的 3.核心是可搶占的,驅動程式 可能在任何時候丟失對處理器的獨佔 4.裝置中斷時非同步事件,可能導致 的併發執行 5.核心還提供了許多可延遲 執行的機制,比如workqueue ...

併發與競態

linux是乙個多工的作業系統,在多個程序同時執行時,就有可能為了競爭同乙個資源發生堵塞。以下是解決的幾種方法 1 訊號量 declare mutex sem if down interruptible sem critical section up sem 2 完成量 declare comple...