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

首頁 > 學(xué)院 > 開發(fā)設(shè)計 > 正文

Linux內(nèi)核同步:同步規(guī)則和說明

2019-11-09 19:02:55
字體:
供稿:網(wǎng)友

什么是同步

像下面的代碼段里邊一樣,有一個棧。一個系統(tǒng)調(diào)用的函數(shù)從棧里邊讀,一個中斷函數(shù)保存數(shù)據(jù)到棧里邊。 這時候,這個棧的數(shù)據(jù)就是一個需要保護的數(shù)據(jù)。

這里寫圖片描述

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

1.發(fā)生中斷: task1在進入臨界區(qū)準(zhǔn)備讀棧的內(nèi)容的時候發(fā)生中斷。中斷函數(shù)放數(shù)據(jù)到棧。task1在中斷返回之后所讀的內(nèi)容,就不是原來預(yù)計的內(nèi)容了。

這里寫圖片描述

2.內(nèi)核搶占:task1進入臨界區(qū)準(zhǔn)備讀棧數(shù)據(jù)的時候,被task2搶占。task2進入臨界區(qū)讀棧。重新調(diào)度會task1的時候,棧里的內(nèi)容已經(jīng)不是原先想要讀的內(nèi)容了。

這里寫圖片描述

3.進程睡眠:task1進入臨界區(qū)準(zhǔn)備讀棧數(shù)據(jù)。但是在kmalloc中進入睡眠。調(diào)度器調(diào)度到task2。task2進入臨界區(qū)讀棧。等task1被喚醒,重新試圖去讀棧數(shù)據(jù)的時候,已經(jīng)不是原來的數(shù)據(jù)了。

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

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

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

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

這里寫圖片描述

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

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

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

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

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

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

這里寫圖片描述

怎么同步

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

多核系統(tǒng)同步,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被其他進程抓著的時候會讓當(dāng)前進程進入睡眠。所以如果critical section包著的代碼很少,這種鎖的效率就不是很高。因為有時候在準(zhǔn)備讓當(dāng)前進程進入睡眠的過程中,鎖可能就已經(jīng)被放開了。 所以spinlock就誕生了。

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

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

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

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

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

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

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

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

在多核系統(tǒng)中,也就是CONFIG_SMP定義了的話

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

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

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

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

保護異常所訪問的數(shù)據(jù)結(jié)構(gòu)

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

競爭條件可以通過信號量避免,因為信號量原語允許進程睡眠到資源變?yōu)榭捎谩W⒁猓盘柫抗ぷ鞣绞皆趩翁幚砥飨到y(tǒng)和多處理器系統(tǒng)上完全不同。

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


保護可延遲函數(shù)所訪問的數(shù)據(jù)結(jié)構(gòu)

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

相反,在多處理器系統(tǒng)上,競爭條件的確存在,因為幾個可延遲函數(shù)可以并發(fā)運行。 以下是在多處理器系統(tǒng)(SMP)中,可延遲函數(shù)訪問的數(shù)據(jù)結(jié)構(gòu)所需的保護

訪問數(shù)據(jù)結(jié)構(gòu)的可延遲函數(shù) 保護
軟中斷 自旋鎖
一個tasklet
多個tasklet 自旋鎖

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

#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.


發(fā)表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發(fā)表
主站蜘蛛池模板: 徐闻县| 清镇市| 公安县| 盐山县| 秀山| 克东县| 同心县| 徐州市| 安平县| 湘乡市| 申扎县| 庆阳市| 凤城市| 二连浩特市| 元氏县| 岫岩| 淳化县| 浦北县| 托里县| 商城县| 克拉玛依市| 阿鲁科尔沁旗| 洞口县| 平陆县| 濮阳县| 扎赉特旗| 石屏县| 长子县| 大足县| 济宁市| 昌都县| 临湘市| 余干县| 景洪市| 开原市| 边坝县| 定日县| 灵川县| 高密市| 武城县| 高密市|