10.1.1 原子整數(shù)操作
創(chuàng)新互聯(lián)專業(yè)為企業(yè)提供武平網(wǎng)站建設、武平做網(wǎng)站、武平網(wǎng)站設計、武平網(wǎng)站制作等企業(yè)網(wǎng)站建設、網(wǎng)頁設計與制作、武平企業(yè)網(wǎng)站模板建站服務,十載武平做網(wǎng)站經(jīng)驗,不只是建網(wǎng)站,更提供有價值的思路和整體網(wǎng)絡服務。typedef struct{
volatile int counter;
}atomic_t;
10.1.2 64位原子操作
10.1.3 原子位操作
10.2 自旋鎖
自旋鎖最多只能被一個可執(zhí)行線程持有。如果一個執(zhí)行線程試圖獲得一個被已經(jīng)持有的自旋鎖,那么該線程就會一直進行忙循環(huán)等待鎖重新可用。要是鎖未被爭用,請求鎖的執(zhí)行線程便立刻得到它,繼續(xù)執(zhí)行。
自旋鎖不應該被長期持有。還可以讓請求線程睡眠,直到鎖重新可用時再喚醒他。這樣處理器不必循環(huán)等待,可以去執(zhí)行其他代碼。這里有兩次明顯的上下文切換,被阻塞的線程要換出和換入。因此,持有自旋鎖的時間最好小于完成兩次上下文切換的耗時。
自旋鎖是不可遞歸的。
自旋鎖可以使用在中斷處理程序中。在中斷處理程序中使用自旋鎖時,一定要在獲取鎖之前,首先禁止本地中斷,否則中斷處理程序就會打斷正持有自旋鎖的代碼,中斷處理程序可能爭用同一鎖。如果中斷發(fā)生在不同的處理器上,即使中斷處理程序在同一鎖上自旋,也不會妨礙鎖的持有者最終釋放鎖。
自旋鎖操作方法
spin_lock();
spin_lock_irq();
spin_lock_irqsave(); 保存本地中斷的狀態(tài),禁止本地中斷,并獲取鎖。
spin_unlock();
spin_unlock_irq();
spin_unlock_irqstore();釋放指定的鎖,并讓本地中斷恢復到以前狀態(tài)
spin_lock_init();
spin_trylock();
spin_is_locked();
10.3 讀——寫自旋鎖
一個或多個讀任務可以并發(fā)的持有讀者鎖;寫鎖最多被一個任務持有,而且此時不能有并發(fā)的讀操作。
讀寫鎖機制照顧讀比照顧寫要多。所以大量讀任務必定會使掛起的寫任務處于饑餓狀態(tài)。
10.4 信號量
linux中的信號量是一種睡眠鎖。如果有一個任務視圖獲得一個不可用的信號量時,信號量會將其推進一個等待隊列,然后讓其睡眠。這時處理器能夠重獲自由,從而去執(zhí)行其他代碼。當持有的信號量可用(被釋放)后,處于等待隊列中的那個任務將被喚醒,并獲得該信號量。
信號量特性:
1、由于爭用信號量的進程在等待鎖重新變?yōu)榭捎脮r會睡眠,所以信號量適用于鎖會被長時間持有的情況。
2、鎖被短時間持有時,使用信號量不合算。因為睡眠、維護等待隊列以及喚醒所花費的開銷可能比鎖被占用的全部時間還要長
3、由于執(zhí)行線程在鎖被爭用時會睡眠,所以只能在進程上下文中才能獲取信號量鎖,因為中斷上下文中是不能進行調(diào)度的
4、你可以在持有信號量的時候去睡眠。
5、占用信號量的時候不能同時占有自旋鎖。因為在等待信號量時可能會睡眠,而持有自旋鎖不允許睡眠。
10.4.1 計數(shù)信號量和二值信號量
信號量可以同時允許任意數(shù)量的鎖持有者,自旋鎖一個時刻只允許一個任務持有。計數(shù)等于1的信號量被稱為二值信號量或者互斥信號量。
10.4.2 創(chuàng)建和初始化信號量
struct semaphore name;
sema_init(&name,count);
-------------------------
static DECLARE_MUTEX(name)
--------------------------
sema_init(sem,count); sem是指針,count指數(shù)量
--------------------------
init_MUTEX(sem);
10.4.3 使用信號量
sema_init(struct semaphore*,int);
init_MUTEX(struct semaphore*);
init_MUTEX_LOCKED(struct semaphore*); 以計數(shù)值0初始化動態(tài)創(chuàng)建的信號量
down_interruptible(struct semaphore*);以試圖獲取指定的信號量,如果信號量已被爭用,則進入可中斷睡眠狀態(tài)
down(struct semaphore*)以試圖獲取指定的信號量,如果信號量已被爭用,則進入不可中斷睡眠狀態(tài)
down_trylock(struct semaphore*);
up(struct semaphore*);
10.5 讀-寫信號量
10.6 互斥體
1、任何時刻只有一個任務可以持有mutex
2、給mutex上鎖者負責給其解鎖——不能在一個上下文中鎖定一個mutex,在另一個上下文中開啟。
3、遞歸上鎖和解鎖是不允許的
4、當持有一個mutex時,進程不可以退出
5、mutex不能再中斷或者下半部使用,即使使用mutex_trylock()也不行
6、mutex只能通過官方API管理。
10.7 完成變量
如果在內(nèi)核中,一個任務需要發(fā)出信號通知另一任務發(fā)生了某個特定事件,利用完成變量是使得兩個任務得以同步的簡單方法。如果一個任務要執(zhí)行一些工作時,另一個任務就會在完成變量上等待。當這個任務完成工作后,會使用完成變量去喚醒在等待的任務。例如:當子進程執(zhí)行或者退出時,vfork()系統(tǒng)調(diào)用使用完成變量喚醒父進程。
在一個指定的完成變量上,需要等待的任務調(diào)用wait_for_completion()來等待特定事件。當特定事件發(fā)生后,產(chǎn)生事件的任務調(diào)用complete()來發(fā)送信號喚醒正在等待的任務。
10.8 BLK:大內(nèi)核鎖
BKL是一個全局自旋鎖,使用它主要是為了方便實現(xiàn)從linux最初的SMP過渡到細粒度加鎖機制。特性:
1、持有BKL的任務可以睡眠。當任務無法調(diào)度時,鎖會自動被丟棄;當任務被調(diào)度時,鎖又重新獲得
2、BKL是一種遞歸鎖。一個進程可以多次請求一個鎖。
3、BKL只可以用在進程上下文中。
4、新的用戶不允許使用BKL。
10.9 順序鎖
seq鎖對寫者更有利。只要沒有其他寫者,寫鎖總是能夠被成功獲得。讀者不會影響寫鎖。
seq鎖在如下情況下是理想選擇:
1、數(shù)據(jù)存在很多讀者
2、寫者較少
3、雖然寫者較少,但是你希望寫優(yōu)先于讀,而且不允許讀讓寫?zhàn)囸I
4、你的數(shù)據(jù)很簡單,如簡單結構,甚至是簡單的整形——在某些場合,你是不能使用原子量的。
10.10 禁止搶占
preempt_disable();增加搶占計數(shù),從而禁止搶占
preempt_enable();減少搶占計數(shù),并當該值將為0時檢查和執(zhí)行被掛起的需調(diào)度任務
preempt_enable_no_resched();激活內(nèi)核搶占但不再檢查任何被掛起的需調(diào)度任務
preempt_count(); 返回搶占計數(shù)
為了用更簡潔的方法解決每個處理器上的數(shù)據(jù)訪問問題,可以通過get_cpu()獲得處理器編號。這個函數(shù)在返回當前處理器編號前會首先關閉內(nèi)核搶占。
10.11 順序和屏障
編譯器和處理器為了提高效率,可能對讀和寫重新排序。所有可能重新排序和寫的處理器提供了機器指令來確保順序要求。同樣也可以指示編譯器不要給定點周圍的指令序列進行重新排序,這些確保順序的指令成為屏障。
rmb()方法提供了一個讀內(nèi)存屏障。
wmb()寫內(nèi)存屏障
mb()讀寫屏障
read_barrier_depends()是rmb()的變種。僅僅是針對后續(xù)讀操作所依靠的那些載入。因為屏障后的讀操作依賴于屏障前的讀操作,因此,該屏障確保屏障前的讀操作在屏障后的讀操作之前完成。
smp_rmb();
smp_reab_barrier_depends();
smp_wmb();
smp_mb();
barrier();阻止編譯器跨屏障對載入或存儲操作進行優(yōu)化