以文本方式查看主題 - 曙海教育集團(tuán)論壇 (http://www.xinguifushi.cn/bbs/index.asp) -- Linux驅(qū)動(dòng)開發(fā) (http://www.xinguifushi.cn/bbs/list.asp?boardid=33) ---- Linux驅(qū)動(dòng)程序開發(fā) - 內(nèi)核同步技術(shù) (http://www.xinguifushi.cn/bbs/dispbbs.asp?boardid=33&id=1704) |
||||||||||||||||||||||||||||||
-- 作者:wangxinxin -- 發(fā)布時(shí)間:2010-11-24 9:20:31 -- Linux驅(qū)動(dòng)程序開發(fā) - 內(nèi)核同步技術(shù) 序言 就像我們?cè)诓僮飨到y(tǒng)里學(xué)習(xí)的那樣,如果多個(gè)程序(進(jìn)程或線程)同時(shí)訪問(wèn)臨界區(qū)數(shù)據(jù)就會(huì)發(fā)生競(jìng)爭(zhēng)。存在競(jìng)爭(zhēng)條件的程序會(huì)產(chǎn)生不可預(yù)料的結(jié)果。消除競(jìng)爭(zhēng)的方法一般就是同步的訪問(wèn)臨界區(qū)數(shù)據(jù)(原子訪問(wèn))。Linux內(nèi)核提供了多種技術(shù)用來(lái)實(shí)現(xiàn)內(nèi)核同步操作。下面我們就分別介紹。 內(nèi)核同步技術(shù) Linux內(nèi)核是多進(jìn)程、多線程的操作系統(tǒng),它提供了相當(dāng)完整的內(nèi)核同步方法。作為一個(gè)總結(jié),我們先列出內(nèi)核同步方法列表,這樣我們可以從總體上對(duì)內(nèi)核同步技術(shù)有個(gè)了解,然后我們這分別對(duì)每個(gè)同步技術(shù)做詳細(xì)介紹。
鎖機(jī)制是一種廣泛使用的同步技術(shù),Linux內(nèi)核中最常見(jiàn)的鎖就是自旋鎖(spin lock)。自旋鎖被設(shè)計(jì)工作在多個(gè)處理器上(SMP),它只能被一個(gè)CPU上的一個(gè)進(jìn)程(線程)所持有。它也可以工作在支持搶占的單處理器上。如果另一個(gè)進(jìn)程或線程試圖獲取一個(gè)被持有的自旋鎖,那么它就會(huì)在該鎖上自旋(循環(huán)的執(zhí)行一小段代碼)直到該鎖被釋放。從這個(gè)意義上說(shuō),自旋鎖是忙等待的,這就會(huì)特別浪費(fèi)處理器的時(shí)間,因此自旋鎖不應(yīng)該被長(zhǎng)時(shí)間持有。對(duì)于單處理器并且不可搶占的內(nèi)核來(lái)說(shuō),自旋鎖什么也不作。
需要強(qiáng)調(diào)的是,自旋鎖別設(shè)計(jì)用于多處理器的同步機(jī)制,對(duì)于單處理器,內(nèi)核在編譯時(shí)不會(huì)引入自旋鎖機(jī)制,對(duì)于可搶占的內(nèi)核,它僅僅被用于設(shè)置內(nèi)核的搶占機(jī)制是否開啟的一個(gè)開關(guān),也就是說(shuō)加鎖和解鎖實(shí)際變成了禁止或開啟內(nèi)核搶占功能。如果內(nèi)核不支持搶占,那么自旋鎖根本就不會(huì)編譯到內(nèi)核中。 內(nèi)核中使用spinlock_t類型來(lái)表示自旋鎖,它定義在<linux/spinlock_types.h>:
對(duì)于不支持SMP的內(nèi)核來(lái)說(shuō),struct raw_spinlock_t什么也沒(méi)有,是一個(gè)空結(jié)構(gòu)。對(duì)于支持多處理器的內(nèi)核來(lái)說(shuō),struct raw_spinlock_t定義為
slock表示了自旋鎖的狀態(tài),“1”表示自旋鎖處于解鎖狀態(tài)(UNLOCK),“0”表示自旋鎖處于上鎖狀態(tài)(LOCKED)。
break_lock表示當(dāng)前是否由進(jìn)程在等待自旋鎖,顯然,它只有在支持搶占的SMP內(nèi)核上才起作用。 自旋鎖的實(shí)現(xiàn)是一個(gè)復(fù)雜的過(guò)程,說(shuō)它復(fù)雜不是因?yàn)樾枰嗌俅a或邏輯來(lái)實(shí)現(xiàn)它,其實(shí)它的實(shí)現(xiàn)代碼很少。自旋鎖的實(shí)現(xiàn)跟體系結(jié)構(gòu)關(guān)系密切,核心代碼基本也是由匯編語(yǔ)言寫成,與體協(xié)結(jié)構(gòu)相關(guān)的核心代碼都放在相關(guān)的<asm/>目錄下,比如<asm/spinlock.h>。對(duì)于我們驅(qū)動(dòng)程序開發(fā)人員來(lái)說(shuō),我們沒(méi)有必要了解這么spinlock的內(nèi)部細(xì)節(jié),如果你對(duì)它感興趣,請(qǐng)參考閱讀Linux內(nèi)核源代碼。對(duì)于我們驅(qū)動(dòng)的spinlock接口,我們只需包括<linux/spinlock.h>頭文件。在我們?cè)敿?xì)的介紹spinlock的API之前,我們先來(lái)看看自旋鎖的一個(gè)基本使用格式:
從使用上來(lái)說(shuō),spinlock的API還很簡(jiǎn)單的,一般我們會(huì)用的的API如下表,其實(shí)它們都是定義在<linux/spinlock.h>中的宏接口,真正的實(shí)現(xiàn)在<asm/spinlock.h>中
spinlock有兩種初始化形式,一種是靜態(tài)初始化,一種是動(dòng)態(tài)初始化。對(duì)于靜態(tài)的spinlock對(duì)象,我們用 SPIN_LOCK_UNLOCKED來(lái)初始化,它是一個(gè)宏。當(dāng)然,我們也可以把聲明spinlock和初始化它放在一起做,這就是 DEFINE_SPINLOCK宏的工作,因此,下面的兩行代碼是等價(jià)的。
spin_lock_init 函數(shù)一般用來(lái)初始化動(dòng)態(tài)創(chuàng)建的spinlock_t對(duì)象,它的參數(shù)是一個(gè)指向spinlock_t對(duì)象的指針。當(dāng)然,它也可以初始化一個(gè)靜態(tài)的沒(méi)有初始化的spinlock_t對(duì)象。
內(nèi)核提供了三個(gè)函數(shù)用于獲取一個(gè)自旋鎖。
spin_lock:獲取指定的自旋鎖。 spin_lock_irq:禁止本地中斷并獲取自旋鎖。 spin_lock_irqsace:保存本地中斷狀態(tài),禁止本地中斷并獲取自旋鎖,返回本地中斷狀態(tài)。 自旋鎖是可以使用在中斷處理程序中的,這時(shí)需要使用具有關(guān)閉本地中斷功能的函數(shù),我們推薦使用 spin_lock_irqsave,因?yàn)樗鼤?huì)保存加鎖前的中斷標(biāo)志,這樣就會(huì)正確恢復(fù)解鎖時(shí)的中斷標(biāo)志。如果spin_lock_irq在加鎖時(shí)中斷是關(guān)閉的,那么在解鎖時(shí)就會(huì)錯(cuò)誤的開啟中斷。 另外兩個(gè)同自旋鎖獲取相關(guān)的函數(shù)是: spin_trylock():嘗試獲取自旋鎖,如果獲取失敗則立即返回非0值,否則返回0。 spin_is_locked():判斷指定的自旋鎖是否已經(jīng)被獲取了。如果是則返回非0,否則,返回0。
同獲取鎖相對(duì)應(yīng),內(nèi)核提供了三個(gè)相對(duì)的函數(shù)來(lái)釋放自旋鎖。 spin_unlock:釋放指定的自旋鎖。 spin_unlock_irq:釋放自旋鎖并激活本地中斷。 spin_unlock_irqsave:釋放自旋鎖,并恢復(fù)保存的本地中斷狀態(tài)。
如果臨界區(qū)保護(hù)的數(shù)據(jù)是可讀可寫的,那么只要沒(méi)有寫操作,對(duì)于讀是可以支持并發(fā)操作的。對(duì)于這種只要求寫操作是互斥的需求,如果還是使用自旋鎖顯然是無(wú)法滿足這個(gè)要求(對(duì)于讀操作實(shí)在是太浪費(fèi)了)。為此內(nèi)核提供了另一種鎖-讀寫自旋鎖,讀自旋鎖也叫共享自旋鎖,寫自旋鎖也叫排他自旋鎖。
讀寫自旋鎖的使用也普通自旋鎖的使用很類似,首先要初始化讀寫自旋鎖對(duì)象:
在讀操作代碼里對(duì)共享數(shù)據(jù)獲取讀自旋鎖:
在寫操作代碼里為共享數(shù)據(jù)獲取寫自旋鎖:
需要注意的是,如果有大量的寫操作,會(huì)使寫操作自旋在寫自旋鎖上而處于寫?zhàn)囸I狀態(tài)(等待讀自旋鎖的全部釋放),因?yàn)樽x自旋鎖會(huì)自由的獲取讀自旋鎖。
讀寫自旋鎖的函數(shù)類似于普通自旋鎖,這里就不一一介紹了,我們把它列在下面的表中。
信號(hào)量,或旗標(biāo),就是我們?cè)诓僮飨到y(tǒng)里學(xué)習(xí)的經(jīng)典的P/V原語(yǔ)操作。
P:如果信號(hào)量值大于0,則遞減信號(hào)量的值,程序繼續(xù)執(zhí)行,否則,睡眠等待信號(hào)量大于0。 V:遞增信號(hào)量的值,如果遞增的信號(hào)量的值大于0,則喚醒等待的進(jìn)程。 信號(hào)量的值確定了同時(shí)可以有多少個(gè)進(jìn)程可以同時(shí)進(jìn)入臨界區(qū),如果信號(hào)量的初始值始1,這信號(hào)量就是互斥信號(hào)量(MUTEX)。對(duì)于大于1的非0值信號(hào)量,也可稱為計(jì)數(shù)信號(hào)量(counting semaphore)。對(duì)于一般的驅(qū)動(dòng)程序使用的信號(hào)量都是互斥信號(hào)量。 |
符合您条件的共有1条 ,第:1 页/共 1 页 | [1] |