一、自旋鎖和互斥鎖的實現
基於硬件原語的一些抽象(比如:中斷禁用、原子操作指令),怎么實現?可以參考清華大學操作公開課(向勇、陳渝老師講的),以下摘抄一部分實現代碼來實現抽象。
Test And Set
bool Test_And_Set(bool* flag) { bool rv = *flag; *flag = TRUE; return rv; }
這是一條機器指令,這條機器指令完成了通常操作的讀寫兩條機器指令的工作,完成了三件事情:
- 從內存中讀取值
- 測試該值是否為1(然后返回真或假)
- 內存值設置為1
Exchange
void Exchange(bool *a, bool *b) { bool tmp = *a; *a = *b; *b = tmp; }
雖然這兩個指令看起來由幾條小指令組成,但是它已經被封裝成了一條機器指令,這就意味着它在執行的時候不會被打斷,不允許出現中斷或切換,這就是機器指令的語義保證。在此基礎上完成互斥。

這里看到如果鎖狀態value為1,表示臨界區現在被人占用,已經上鎖了,這時調用Lock::Acquire()不能得到鎖,那么它會在這里死循環,不斷測試value的值。這種空轉全用來消耗任務的時間片,顯然是可以有優化空間的。例如發現獲取鎖失敗,則將任務置為睡眠狀態,掛入到等待隊列。

class Lock{ int value = 0; } Lock::Acquire(){ int key = 1; while(1 == key){ exchange(lock, key); } } Lock::Reease(){ value = 0; }//本質上就是用一個機器指令完成以下操作1、讀取當前值。2、把當前值對應的內存設置為1。
二、自旋鎖和互斥鎖的區別
- 互斥鎖:線程會從sleep(加鎖)——>running(解鎖),過程中有上下文的切換,cpu的搶占,信號的發送等開銷;
- 自旋鎖:線程一直是running(加鎖——>解鎖),死循環檢測鎖的標志位,機制不復雜,主要用於SMP或內核可搶占下,因為在內核不可搶占下,cpu在執行空操作。
- 互斥鎖的起始原始開銷要高於自旋鎖,但是基本是一勞永逸,臨界區持鎖時間的大小並不會對互斥鎖的開銷造成影響,而自旋鎖是死循環檢測,加鎖全程消耗cpu,起始開銷雖然低於互斥鎖,但是隨着持鎖時間,加鎖的開銷是線性增長
三、自旋鎖和互斥鎖的對應的應用
互斥鎖用於臨界區持鎖時間比較長的操作,比如下面這些情況都可以考慮
1、 臨界區有IO操作
2 、臨界區代碼復雜或者循環量大
3 、臨界區競爭非常激烈
4、 單核處理器
至於自旋鎖就主要用在臨界區持鎖時間非常短且CPU資源不緊張的情況下。
自旋-互斥鎖
下面的英文介紹了混合互斥鎖和混合自旋鎖,但是不管是第一段說的先上非阻塞鎖后上阻塞鎖,還是第二段說的先自旋上鎖后進行休眠,反正思路都是先自旋上鎖一定時間后在上互斥鎖,這種自旋-互斥鎖適合各線程持鎖時間間隔跨度比較大的情況。
A hybrid mutex behaves like a spinlock at first on a multi-core system. If a thread cannot lock the mutex, it won't be put to sleep immediately, since the mutex might get unlocked pretty soon, so instead the mutex will first behave exactly like a spinlock. Only if the lock has still not been obtained after a certain amount of time (or retries or any other measuring factor), the thread is really put to sleep. If the same system runs on a system with only a single core, the mutex will not spinlock, though, as, see above, that would not be beneficial.
A hybrid spinlock behaves like a normal spinlock at first, but to avoid wasting too much CPU time, it may have a back-off strategy. It will usually not put the thread to sleep (since you don't want that to happen when using a spinlock), but it may decide to stop the thread (either immediately or after a certain amount of time) and allow another thread to run, thus increasing chances that the spinlock is unlocked (a pure thread switch is usually less expensive than one that involves putting a thread to sleep and waking it up again later on, though not by far).
