并發(fā)指的是多個(gè)執(zhí)行單元同時(shí)、并行被執(zhí)行,而并發(fā)的執(zhí)行單元對(duì)共享資源的訪問則很容易導(dǎo)致競(jìng)態(tài)
linux內(nèi)核中主要競(jìng)態(tài)
1.多對(duì)稱處理器的多個(gè)CPU? 2.單CPU內(nèi)進(jìn)程與搶占它的進(jìn)程 3.中斷(硬中斷、軟中斷、Tasklet、下半部)與進(jìn)程之間
訪問共享內(nèi)存資源的代碼區(qū)稱為“臨界區(qū)”,臨界區(qū)需要被以某種互斥機(jī)制加以保護(hù),中斷屏蔽、原子操作、自旋鎖和信號(hào)量等
是linux設(shè)備驅(qū)動(dòng)中可采用的互斥途徑。
這幾個(gè)互斥的介紹:
1.中斷屏蔽,這個(gè)主要用于單CPU,中斷屏蔽將使得中斷和進(jìn)程之間的并發(fā)不再發(fā)生。使用方法:
local_irq_disable();//屏蔽中斷
...
...
臨界區(qū)
...
local_irq_enable();//開中斷
由于linux的異步IO、進(jìn)程調(diào)度等很多重要的操作都依賴于中斷,中斷對(duì)于內(nèi)核的運(yùn)行非常重要,在屏蔽中斷期間所有的中斷都無法處理,
因此長時(shí)間的屏蔽中斷很危險(xiǎn),有可能導(dǎo)致數(shù)據(jù)丟失甚至系統(tǒng)崩潰。所以這個(gè)不作為重點(diǎn)討論。
**********************************************************************************************************************************************************
2.原子操作,原子操作是一系列的不能被打斷的操作。linux內(nèi)核提供了一系列的函數(shù)來實(shí)現(xiàn)內(nèi)核中的原子操作,這些函數(shù)分為2類,分別針對(duì)位和整型變量
進(jìn)行原子操作。
實(shí)現(xiàn)原子操作的步驟:
1.定義原子變量并設(shè)置變量值
void atomic_set(atomic_t *v , int i); //設(shè)置原子變量值為i
atomic_t v = ATOMIC_INIT(0);?//定義原子變量v,初始化為0
2.獲取原子變量的值
atomic_read(atomic_t *v);
3.原子變量加減操作
void atomic_add(int i,atomic_t *v);//原子變量加i
void atomic_sub(int i ,atomic_t *v);//原子變量減i
4.原子變量自增/自減
void atomic_inc(atomic_t *v);//自增1
void atomic_dec(atomic_t *v);//自減1
5.操作并測(cè)試:對(duì)原子變量執(zhí)行自增、自減后(沒有加)測(cè)試其是否為0,如果為0返回true,否則返回false。
int atomic_inc_and_test(atomic_t *v);
int atomic_dec_and_test(atomic_t *v);
int atomic_sub_and_test(int i ,atomic_t *v);
6.操作并返回
int atomic_add_return(int i , atomic_t *v);
int atomic_sub_return(int i , atomic_t *v);
int atomic_inc_return(atomic_t * v);
int atomic_dec_return(atomic_t * v);
**********************************************************************************************************************************************************
3.自旋鎖
自旋鎖是一個(gè)忙鎖,它在一個(gè)小的循環(huán)內(nèi)不斷的重復(fù)測(cè)試并設(shè)置的操作。
自旋鎖保護(hù)臨界區(qū)的特點(diǎn):臨界區(qū)要小,并且臨界區(qū)內(nèi)不能有導(dǎo)致睡眠的操作,否則可能引起系統(tǒng)崩潰。自旋鎖可能導(dǎo)致系統(tǒng)死鎖,
引發(fā)這個(gè)問題最常見的情況是遞歸使用一個(gè)自旋鎖。
自旋鎖的操作步驟:
1.定義自旋鎖
spinlock_t lock;
2.初始化自旋鎖
spin_lock_init(lock);這是個(gè)宏,它用于動(dòng)態(tài)初始化自旋鎖lock;
3.獲得自旋鎖
spin_lock(lock);該宏用于加鎖,如果能夠立即獲得鎖,它就能馬上返回,否則,他將自旋在那里,直到該自旋鎖的保持者釋放。
spin_trylock(lock);能夠獲得,則返回真,否則返回假,實(shí)際上是不在原地打轉(zhuǎn)而已。
4.釋放自旋鎖
spin_unlock(lock);
與上面的兩個(gè)配對(duì)使用。
例子:
spinlock_t lock;
spin_lock_init(&lock);
spin_lock(&lock);? //獲取自旋鎖,保護(hù)臨界區(qū)
。。。。臨界區(qū)
spin_unlock(&lock);//釋放自旋鎖
自旋鎖不關(guān)心鎖定的臨界區(qū)究竟是如何執(zhí)行的。不管是讀操作還是寫操作,實(shí)際上,對(duì)共享資源進(jìn)行讀取的時(shí)候是應(yīng)該可以允許多個(gè)執(zhí)行單元同時(shí)
訪問的,那么這樣的話,自旋鎖就有了弊端。于是便衍生出來一個(gè)讀寫鎖。
它保留了自旋的特性,但在對(duì)操作上面可以允許有多個(gè)單元進(jìn)程同時(shí)操作。當(dāng)然,讀和寫的時(shí)候不能同時(shí)進(jìn)行。
現(xiàn)在又有問題了,如果我第一個(gè)進(jìn)程寫共享資源,第二個(gè)進(jìn)程讀的話,一旦寫了,那么就讀不到了,可能寫的東西比較多,但是第二個(gè)進(jìn)程讀很小,那么
能不能第一個(gè)進(jìn)程寫的同時(shí),我第二個(gè)進(jìn)程讀呢?
當(dāng)然可以,那么引出了順序鎖的概念。都是一樣的操作。
**********************************************************************************************************************************************************
4.信號(hào)量
是用于保護(hù)臨界區(qū)的一種常用的方法,它的使用與自旋鎖差不多,但是它不在原地打轉(zhuǎn),當(dāng)獲取不到信號(hào)量時(shí)候,進(jìn)程會(huì)進(jìn)入休眠等待狀態(tài)。
主要操作:
1.定義sem信號(hào)量
struct semaphore sem;
2.初始化信號(hào)量
void sema_init(struct semaphore *sem, int val);
初始化信號(hào)量,并設(shè)置sem的值為val
初始化的時(shí)候還可以這樣用,init_MUTEX(sem),這是個(gè)宏 #define init_MUTEX(sem) sema_init(sem , 1)
?????? init_MUTEX_LOCKED(sem),這是個(gè)宏 #define init_MUTEX_LOCKED(sem) sema_init(sem , 0)
3.獲得信號(hào)量
void down(struct semaphore * sem);
該函數(shù)用于獲得信號(hào)量sem,他會(huì)導(dǎo)致睡眠,所以不能在中斷中使用。
int down_interruptible(struct semaphore* sem);
與上面功能類似,因?yàn)閐own進(jìn)入睡眠狀態(tài)的進(jìn)程不能被信號(hào)打斷,而它能被信號(hào)打斷,信號(hào)也會(huì)導(dǎo)致該函數(shù)返回。
int down_trylock(struct semaphore * sem);
4.釋放信號(hào)量
void up(struct semaphore * sem);
該函數(shù)用于釋放信號(hào)量,同時(shí)喚醒等待者。
信號(hào)量一般這樣使用:
DECLARE_MUTEX(sem);
down(&sem);
.....臨界區(qū)
up(&sem);
linux自旋鎖和信號(hào)量采用的“獲取鎖-訪問臨界區(qū)-釋放鎖”的方式。
*************************************************************************************************************************
5.互斥體
互斥體和信號(hào)量基本上差不多。不介紹了。
總結(jié):并發(fā)和競(jìng)態(tài)廣泛存在,這幾個(gè)機(jī)制是解決問題的好方法,中斷屏蔽很少單獨(dú)使用,原子操作只能針對(duì)整數(shù)進(jìn)行,因此,自旋鎖和信號(hào)量應(yīng)用最為廣泛。
自旋鎖會(huì)導(dǎo)致死循環(huán),鎖定期間不允許阻塞,因此要求鎖定的臨界區(qū)要小。信號(hào)量允許臨界區(qū)阻塞,可以適用于臨界區(qū)較大的情況。讀寫自旋鎖和讀寫信號(hào)量是
放寬了條件的自旋鎖和信號(hào)量,他們?cè)试S多個(gè)進(jìn)程并發(fā)的讀取共享空間。
評(píng)論
查看更多