新的排隊spin lock 有序和無序

2021-08-25 01:27:17 字數 2471 閱讀 5323

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並喚醒它,而...