2.6.25核心實現了新的自旋鎖,叫做ticket spin_lock,ticket就是排隊的意思,就像看電影時拿著票有序入場一樣,新的自旋鎖不再是亂搶自旋鎖了,而是有序地獲得自旋鎖,這樣就消除了一些不必要的混亂。這樣做的初衷是什麼呢?首先看看自旋鎖的意義,它是一種十分高效的鎖,得不到鎖的時候不是睡眠而是自旋,自旋就是忙等,這樣就免去了睡 眠-切換-喚醒-切換的開銷,畢竟乙個程序睡眠必然導致一次硬切換,而喚醒仍然需要一次硬切換。但是在忙等期間,cpu實際上沒有做什麼有意義的事情,這 是一點小小的弊端,但是任何事必須圖一方面,和睡眠-切換-喚醒的開銷比起來,這麼做是十分有意義的。另外要明白的是,當前實現的自旋鎖的爭搶實體實際上 是cpu,而不是程序,在單cpu的非搶占核心上,自旋鎖是不必要的,在單cpu的搶占核心,自旋鎖實際就是禁用了搶占而已,只有在多cpu的環境下,自旋鎖作為鎖的意義才真正存在,所以我們說是cpu獲得了自旋鎖而不是別的。要了解新自旋鎖的意義還要了解老自旋鎖的實現。老的自旋鎖是乙個整數,在cpu 企圖獲得鎖的時候要將此數減一,然後看看是否為0,如果為0,那麼就獲得了鎖,如果為負數就說明別的cpu比此cpu先獲得了鎖,然後此cpu進入忙等, 等待占有鎖的cpu釋放鎖從而將鎖置為1,然後它再次將其減一後與0比較。這麼實現可以看出,乙個cpu企圖獲得鎖時所探測到的鎖的值是負數並且絕對值越大,那麼就有越多的cpu在爭搶這個自旋鎖,這看起來沒有問題,就像踢足球一樣,那麼多人搶乙個球,但是足球有個人技術,團隊合作在裡面,有輸有贏的結果,而自旋鎖就不一樣了,所有的cpu要公平競爭,沒有團隊,沒有個人技術,但是這個實現真的就很公平嗎?如果不考慮硬體告訴快取,那麼它可能還是比較公平的,但是幾乎每個cpu都有硬體快取記憶體,如果乙個cpu得到了自旋鎖那麼資訊就會被讀入該cpu的快取行,後來它釋放了這個自旋鎖,但是馬上它又去爭 搶同乙個鎖,這樣這個cpu對於別的cpu就是不公平的,它再次得到自旋鎖的可能性要比別的cpu要大,因此,老的自旋鎖實現方案看似公平實際不公平,按道理應該讓等待時間最長的cpu獲得自旋鎖。要得到這樣的效果,改進點已經很明確了,就是增加乙個佇列,這個佇列的元素按照等待時間排隊,資料結構也很簡單,增加乙個list_head欄位即可,如果這麼實現當然比較好,比較規則,比較規範,但是不是那麼藝術和高效,於是新的ticket自旋鎖由運而生。
以上從理論角度闡述了老的自旋鎖的實現,下面看一下具體的**,主要是純粹的獲得鎖和釋放鎖的**,不再討論開關搶占的內容:
#define spin_lock_string /
"/n1:/t" /
"lock ; decb %0/n/t" / //引數0實際上就是lock->slock,這裡減1
"jns 3f/n" / //若為0則結束,成功獲得鎖。
"2:/t" / //否則,自旋忙等
"rep;nop/n/t" /
"cmpb $0,%0/n/t" /
"jle 2b/n/t" /
"jmp 1b/n" /
"3:/n/t"
#define spin_unlock_string /
"movb $1,%0" / //將lock->slock的值設定為1
:"=m" (lock->slock) : : "memory"
那 麼ticket自旋鎖是如何實現的呢?它實際上是乙個16位的數,被分為高8位和低8位,高8位代表的是爭搶者的順序號,也就是說高8位從小到大的順序正 是爭搶者獲得鎖的順序,低8位代表擁有者的資訊。具體過程就是,乙個cpu請求自旋鎖的時候,首先遞加自旋鎖的高8位存入乙個變數,然後比較是否和低8位 相等,若不等則忙等,忙等中不斷比較先前存入的變數和自旋鎖的低8位是否相等,一旦相等,則代表成功獲得鎖,結束爭搶過程。注意,只有在乙個擁有鎖的 cpu釋放鎖的時候才會導致自旋鎖的低8位加1。說了等於白說,還是看**實現吧:
static inline void __raw_spin_lock(__raw_spinlock_t *lock)
short inc = 0x0100;
__asm__ __volatile__ (
lock_prefix "xaddw %w0, %1/n" //高8位加1,交換兩引數,效果就是lock的高8位加1
"1:/t"
"cmpb %h0, %b0/n/t" //比較高8位和低8位
"je 2f/n/t" //相等就結束,成功獲得鎖
"rep ; nop/n/t" //否則忙等
"movb %1, %b0/n/t"
/* don't need lfence here, because loads are in-order */
"jmp 1b/n"
"2:"
:"+q" (inc), "+m" (lock->slock)
:"memory", "cc");
static inline void __raw_spin_unlock(__raw_spinlock_t *lock)
__asm__ __volatile__(
unlock_lock_prefix "incb %0" //我們看到自旋鎖的低8位遞增了1
:"+m" (lock->slock)
:"memory", "cc");
新的排隊spin lock 有序和無序
2.6.25核心實現了新的自旋鎖,叫做ticket spin lock,ticket就是排隊的意思,就像看電影時拿著票有序入場一樣,新的自旋鎖不再是亂搶自旋鎖了,而是有序地獲得自旋鎖,這樣就消除了一些不必要的混亂。這樣做的初衷是什麼呢?首先看看自旋鎖的意義,它是一種十分高效的鎖,得不到鎖的時候不是睡...
spinlock的設計和實現
在linux的核心中,spin lock用在多處理器環境中。當乙個cpu訪問乙個臨界資源 critical section 的時候,需要預先取得spin lock,如果取不到的話,它就在空迴圈 等待,直到另外的cpu釋放spin lock。由於涉及到多個處理器,spin lock的效率非常重要。因為...
mutex和spin lock的區別
mutex和spin lock的區別和應用 sleep waiting和busy waiting的區別 2011 10 19 11 43 訊號量mutex是sleep waiting。就是說當沒有獲得mutex時,會有上下文切換,將自己 加到忙等待佇列中,直到另外乙個執行緒釋放mutex並喚醒它,而...