国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁 > 學院 > 開發設計 > 正文

Linux內核同步:同步規則和說明

2019-11-09 18:29:12
字體:
來源:轉載
供稿:網友

什么是同步

像下面的代碼段里邊一樣,有一個棧。一個系統調用的函數從棧里邊讀,一個中斷函數保存數據到棧里邊。 這時候,這個棧的數據就是一個需要保護的數據。

這里寫圖片描述

在多進程系統中,有以下幾種情況下會出現race condition。(這里只討論單核的情況)

1.發生中斷: task1在進入臨界區準備讀棧的內容的時候發生中斷。中斷函數放數據到棧。task1在中斷返回之后所讀的內容,就不是原來預計的內容了。

這里寫圖片描述

2.內核搶占:task1進入臨界區準備讀棧數據的時候,被task2搶占。task2進入臨界區讀棧。重新調度會task1的時候,棧里的內容已經不是原先想要讀的內容了。

這里寫圖片描述

3.進程睡眠:task1進入臨界區準備讀棧數據。但是在kmalloc中進入睡眠。調度器調度到task2。task2進入臨界區讀棧。等task1被喚醒,重新試圖去讀棧數據的時候,已經不是原來的數據了。

所以所謂同步(Synchronization)就是防止在上述情況下出現race condition的方法。 linux內核提供一些同步方法。

For single core Disabling PReemption (or interrupts) Prevent other tasks (or ISRs) from runningFor multi-core Atomic Operations Perform multiple actions at onceLocking primitives Prevent other tasks from entering a critical section

對于單核的系統,同步只需要在進入臨界區域之前防止中斷和防止進程搶占,或者防止自身由于不當的操作而進入睡眠即可(比如kmalloc傳入GPF_KERNEL時,會在申請不到內存時進入睡眠)。 對于多核系統,禁止中斷或者禁止搶占,都不能有效防止race conditions(這個會在下面仔細說明)。在多核系統中,需要1.atomic operations 或者2. spinlock,mutex,semaphore等同步的方法,才能防止race conditions。

禁止搶占方式對于單核系統是有效的同步方法,但在多核系統中是無效的。 這里寫圖片描述

這里寫圖片描述

禁止搶占函數接口: 這里寫圖片描述

在單核系統中,如果task和isr都可以訪問要保護的數據,那只禁止搶占是沒有用的,比如下面的情況。 這里寫圖片描述

所以在單核系統中,要保護可以被task和isr同時訪問的數據,需要再禁止中斷。 這里寫圖片描述

但禁止中斷,同樣不能同步多核系統中的數據。而且Linux2.4以后,沒有一個像cli()這樣的函數可以直接把所有CPU上面的中斷都給禁止掉。現在有以下幾個接口可以用來禁止當前CPU的進程。

local_disable() //中斷禁止...local_enable() //中斷使能unsigned long flags;local_irq_save(flags);...local_irq_restore(flags);

內核和用戶控件的同步方法如下: 這里寫圖片描述

這里寫圖片描述

怎么同步

首先要明確同步所保護的對象是全局數據(global data)。 還要確定要保護的全局數據是怎么被訪問的。如下面的幾個順序。 1. 要保護的數據是全局數據否 2. 數據是否是task和isr上下問都在訪問的 3. task在進入臨界區之后,是否可以進入睡眠? 4. 一個CPU的task或者isr進入臨界區中之后,其他CPU也通過task或者isr訪問這個臨界區會怎么樣?

多核系統同步,atomic接口:

這里寫圖片描述

這里寫圖片描述

這里寫圖片描述 這里寫圖片描述

這里寫圖片描述

spinlock

Spin lock

Spin lock is a mutual exclusion mechanism where a process spins (or busy-waits) until the lock becomes availableSpin lock is meaningful in SMP so that a task running in another CPU can release the lockSpin lock is useful when the length of critical section is short so that spinning time < rescheduling overhead

spin_lock, spin_lock_irq, spin_lock_irqsave 這幾種宏的說明

在multi thread程序中,為了給眾多thread進行同步(synchronization)才有了lock算法。 mutex是也是一種同步機制,但這種機制在試圖或者lock,但lock被其他進程抓著的時候會讓當前進程進入睡眠。所以如果critical section包著的代碼很少,這種鎖的效率就不是很高。因為有時候在準備讓當前進程進入睡眠的過程中,鎖可能就已經被放開了。 所以spinlock就誕生了。

1.spinlock與mutex不同,在獲取不到lock的時候不是進入讓當前進程進入睡眠,而是跑一個loop,讓當前進程busy-waiting。所以如果critical section比較少的時候用spinlock會比較高效。 這里寫圖片描述

2.spinlock可以解決所有問題嗎? 不是的。當中斷上下文也可以訪問要保護的數據的時候,只用spin_lock函數是有問題的。因為一個進程抓著spinlock的時候發生了中斷,然后中斷處理函數再準備抓當前的spinlock的時候,會因為之前的進程抓著spinlock而等不到spinlock釋放,就會發生daedlock。 為了解決這樣的場景,登場的是spin_lock_irq函數。這個函數在獲取spinlock的同時,會把中斷disable掉。使用spin_lock_irq函數,在執行critical section的時候就不會發生中斷,也就避免了上面說的問題。

3.但是如果中斷嵌套發生的情況,就不能使用spin_lock_irq函數。因為spin_lock_irq函數無論disable了中斷多少次,只要有一次enable中斷就會被重新打開。這種場景下使用的函數就是spin_lock_irqsave函數。spin_lock_irqsave函數會在disable中斷的同時保存中斷enable狀態還是disable次數。這個函數在中斷會嵌套發生的情況下使用會比較方便,只不過因為要保存當前的enable/disable狀態,所以占用多一點的內存。 這里寫圖片描述

spin_lock (spinlock) 最基本的spinlock,如果不需要使用其他的spinlock接口就用這個。

spin_lock_irq (spin lock irq disable) 這個函數會把所有的中斷都會給disable掉,所以對interactivity等系統的性能有影響。 這個函數一般用在interrupt handler和一般thread共享一個spinlock的時候使用。 但要注意這個函數在spin_unlock_irq的時候,不管disable過多少次中斷,都會把當前的中斷打開。

spin_lock_irqsave (spin lock irq save) spin_lock_irq一樣,但會保存enable,disable的次數。. 如果在spinlock的時候,無法判斷當前的中斷的打開或者關閉狀態的時候使用。

spin lock在單核系統中也是有的,不過和多核系統不同,在沒有定義CONFIG_SMP的時候。

spin_lock() = preempt_disable() spin_lock_irqsave() ==local_irqsave()

在多核系統中,也就是CONFIG_SMP定義了的話

spin_lock() ==preempt_disable() + arch_spin_lock()spin_lock_irqsave() ==local_irqsave() + arch_spin_lock()

在使用spinlock的時候,必須要注意死鎖!!因為一不小心就會在使用spin lock接口的時候出現死鎖。 1.ABBA deadlock示例 這里寫圖片描述 像上面這樣,有兩個tam,mic鎖。在task1獲取tam鎖,到get_free_tam()函數的時候進入睡眠。然后調度到task2在獲取mic鎖,到get_free_mic的時候進入睡眠。重新調度到task1的時候,準備獲取mic鎖,但這個鎖被task2獲取了,所以task1一直loop等待。然后當task2醒來之后準備獲取tam鎖的時候,發現這個被task1獲取,所以task2也一直在那里loop等待task1釋放tam。這時候task1和task2,互相等待對方的釋放鎖,就出現了所謂ABBA的deadlock。 這里可以看到出現這種死鎖的根本原因也是在持有某個鎖的時候進入睡眠!! 所以一般書上說持有spinlock鎖不能進入睡眠也是因為這個。 2. Deadly embrace(indefinite postponement) 這里寫圖片描述 這個很簡單就是獲取了一個鎖,然后跑進去再去試圖獲取同樣的鎖,,當然就不行了~

在自旋鎖,信號量及中斷禁止之間選擇

訪問數據結構的內核控制路徑 單處理器保護 多處理器進一步保護
異常 信號量 無 (????)
中斷 本地中斷禁止 自旋鎖
可延遲函數 無或者自旋鎖 (看下面可延遲函數保護)
異常與中斷 本地中斷禁止 自旋鎖
異常與可延遲函數 本地軟中斷禁止 自旋鎖
中斷與可延遲函數 本地中斷禁止 自旋鎖
異常,中斷與可延遲函數 本地中斷禁止 自旋鎖

保護異常所訪問的數據結構

當一個數據結構僅由異常處理程序訪問時,競爭條件通常是易于理解也易于避免的。 這里注意,上面的意思是數據結構僅由異常訪問的情況,上面的表也是。在讀取修改其他進程也可以訪問到的數據結構的時候還是需要用到自選鎖等。 最常見的產生同步問題的異常就是系統調用服務例程,在這種情況下,CPU運行在內核態而為用戶態程序提供服務。因此,僅由異常訪問的數據結構通常表示一種資源,可以分配給一個或多個進程。

競爭條件可以通過信號量避免,因為信號量原語允許進程睡眠到資源變為可用。注意,信號量工作方式在單處理器系統和多處理器系統上完全不同。

內核搶占不會引起太大問題。如果一個擁有信號量的進程是可以被搶占的,運行在同一個CPU上新進程就可能試圖獲得這個信號量。在這種情況下,讓新進程處于睡眠狀態,而且原來擁有信號量的進程最終會釋放信號量。只有在訪問每CPU變量的情況下,必須顯式地禁用內核搶占。(???)


保護可延遲函數所訪問的數據結構

只被可延遲函數訪問的數據結構需要哪種保護呢?這主要取決于可延遲函數的種類。 比如tasklet和軟中斷本質上有不同的并發度,所以保護方式也有不同。 首先,在單處理器系統上不存在競爭條件。這時因為可延遲函數的執行總是在一個CPU上穿行執行—也就是說,一個可延遲函數不會被另一個可延遲函數中斷。因此,根本不需要同步原語。

相反,在多處理器系統上,競爭條件的確存在,因為幾個可延遲函數可以并發運行。 以下是在多處理器系統(SMP)中,可延遲函數訪問的數據結構所需的保護

訪問數據結構的可延遲函數 保護
軟中斷 自旋鎖
一個tasklet
多個tasklet 自旋鎖

由軟中斷訪問的數據結構必須受到保護,通常使用自旋鎖進行保護,因為同一個軟中斷可以在兩個或多個CPU上并發運行。相反,僅由一個tasklet訪問的數據結構不需要保護,因為同種tasklet不能并發運行。但是,如果數據結構被幾種tasklet訪問,那么,就必須對數據結構進行保護。

#The first of these rules is: never sleep when you are running in an atomic context What that means, with regard to sleeping, is that your driver cannot sleepwhile holding aspinlock, seqlock, or RCU lock. You also cannot sleep if you have disabled interrupts. It is legal to sleep while holding a semaphore, but you should look very carefully at any code that does so. If code sleeps while holding a sema-phore, any other thread waiting for that semaphore also sleeps. So any sleeps that happen while holding semaphores should be short,and yous hould convince your-self that,by holding these maphore,youarenotblockingtheprocessthatwilleven-tually wake you up.


發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
主站蜘蛛池模板: 专栏| 临漳县| 岑溪市| 南乐县| 寻甸| 日喀则市| 镇雄县| 拉孜县| 南安市| 德令哈市| 柏乡县| 师宗县| 金溪县| 资溪县| 炉霍县| 巴林右旗| 交城县| 虞城县| 海门市| 武宁县| 嵊泗县| 五华县| 邻水| 怀来县| 北安市| 南昌市| 临沂市| 岳西县| 双辽市| 昌图县| 大城县| 凤山市| 大荔县| 金坛市| 当阳市| 德钦县| 贵德县| 黄龙县| 海丰县| 科技| 西藏|