1. 程式人生 > >排隊自旋鎖(Ticket spinlocks)

排隊自旋鎖(Ticket spinlocks)

(譯自http://lwn.net/Articles/267968/,作者Jonathan Corbet)
自旋鎖是Linux核心中最底層的互斥機制。因此,它們對核心的安全和效能有很大的影響,人們花很大力氣去優化各種自旋鎖的實現(不同的硬體體系結構會有不同的實現)也就不足為奇了。但是我們的優化之路還沒有走到終點,一個合併到2.6.25版本核心的patch告訴我們能做的還有很多。
在x86架構上的2.6.24版本核心中,自旋鎖用一個整數來表示。當為1時表示這個鎖是可被獲得的。spin_lock()函式被呼叫時,首先原子地對這個整數減1,然後看結果是否為0;如果為0,則鎖被呼叫者獲得;如果為負數,這說明這個鎖已經被別人得到了,然後它就會進入忙等/自旋狀態,一直迴圈到鎖的值變為正,然後再從頭開始,再次嘗試獲得鎖。
當臨界區的程式碼執行完畢後,鎖的所有者會將鎖的值設為1來釋放這個鎖。
這種實現效率很高,尤其在沒有競爭的情況下(實際在大多數情況下都沒有競爭)。想要看鎖的爭用有多激烈也很簡單——鎖的值越小,對鎖進行爭用的處理器越多。但是這種方法有一個弊端:它並不公平。當鎖被釋放後,第一個對這個鎖執行減1操作的處理器將會獲得這個鎖。我們並不能保證等待時間最長的處理器獲得這個鎖;實際上,剛剛釋放了鎖的處理器更容易再次獲得這個鎖,因為這個鎖正好在它的cache中。
有些人希望鎖的不公平不會造成問題;在許多情況下,當鎖的爭用很激烈時,即使不考慮鎖的公平性,爭用也會產生效能問題。Nick Piggin最近重新思考了這個問題,他注意到:

對於一個8核Opteron處理器,自旋鎖的不公平性是無法忽視的,在使用者空間對鎖的測試中,不同的執行緒的執行時間可能會相差兩倍,有些執行緒在嘗試1000000次後才能獲得鎖。

這樣的執行時間的差異自然是無法接受的。鎖的不公平性也會造成延遲問題,因為獲得鎖的時間可能任意長,也就無法對延遲長短做一個保證了。
Nick的迴應是一種新的自旋鎖實現,他將其稱為“排隊自旋鎖”。在它的最初版本中,自旋鎖佔用16位,分為兩個位元組,分別是“Next”欄位和“Owner”欄位。
每個位元組都可以認為是一個入場號,就像商店裡的叫號機,Next欄位表示叫號機即將列印分發的號,Owner欄位表示正在視窗前服務的號,商店的做法能保證顧客按照到達的順序被提供服務。
因此,在新方案中,鎖的初始值(兩部分)被初始化為0。spin_lock()函式首先記錄下鎖的值,然後將Next欄位加1——一次原子操作就能完成這些事情。如果Next欄位在加1之前等於Owner欄位,鎖就會被當前處理器獲得,剩餘工作就能繼續進行。否則處理器就會自旋,直到Owner欄位增長到正確的值(譯註:即函式一開始記錄下的Next欄位的值)。在這種方案中,釋放鎖時只需要將Owner欄位加1即可。
上述的實現也有一些小小的弊端,那就是處理器的數目不能超過256,處理器數量超過這個值的話,當發生激烈地鎖爭用時,不同的處理器可能會獲得相同的排隊號。由此產生的潛在問題是不可容忍的,在很多大型系統中,處理器數量早已超過了256。因此有一個附加的

“big ticket”補丁也被合併到2.6.25版本核心中,它使用一個16位的排隊號,這使處理器數目上限達到了65536。
在舊版本的自旋鎖實現中,發生鎖爭用時所有處理器都要去搶這個鎖。現在他們可以按照到達的順序排隊等候來獲得這個鎖了。多個執行緒的執行時間變得平均了,最大延遲也減小了(而且延遲也變得確定而不是任意長了)。Nick認為,新實現可能會帶來輕微的開銷,但是這個開銷在當代的處理器上非常小,而且相對於發生鎖爭用時出現的cache不命中帶來的開銷可以忽略。核心x86維護者們顯然認為消除激烈爭用帶來的收益高於這小小的開銷,別人大概也會認可吧。

相關推薦

排隊Ticket spinlocks

(譯自http://lwn.net/Articles/267968/,作者Jonathan Corbet) 自旋鎖是Linux核心中最底層的互斥機制。因此,它們對核心的安全和效能有很大的影響,人們花很大力氣去優化各種自旋鎖的實現(不同的硬體體系結構會有不同的實

spin lock與互斥量的區別

自旋鎖(spin lock)與互斥量(mutex)的比較 自旋鎖是一種非阻塞鎖,也就是說,如果某執行緒需要獲取自旋鎖,但該鎖已經被其他執行緒佔用時,該執行緒不會被掛起,而是在不斷的消耗CPU的時間,不停的試圖獲取自旋鎖。 互斥量是阻塞鎖,當某執行緒無法獲取互斥量時,該執行緒

適應不看後悔,看了必懂

自旋鎖 所謂自旋,就是指當有另外一個執行緒來競爭鎖時,這個執行緒會在原地迴圈等待,而不是把該執行緒給阻塞,直到那個獲得鎖的執行緒釋放鎖之後,這個執行緒就可以馬上獲得鎖的。鎖在原地迴圈的時候,是會消耗cpu的,就相當於在執行一個啥也沒有的for迴圈。 本來一個執行緒把鎖釋放之後,當前執行緒

[Linux]互斥機制中斷遮蔽、原子操作、、訊號量

基本概念 臨界區 對某段程式碼而言,可能會在程式中多次被執行,每次執行的過程我們稱作程式碼的執行路徑。 當兩個或多個程式碼路徑要競爭共同的資源的時候,該程式碼段就是臨界區。 互斥機制 訪問共享資源的程式碼叫做臨界區。共享資源被多個執行緒需要

嵌入式 spinlock詳解以及使用示例

1、使用示例: #include <linux/module.h> #include <linux/moduleparam.h> #include <linux/types.h> #include <linux/timer.h>

聊聊高併發實現幾種

在聊聊高併發(七)實現幾種自旋鎖(二) 這篇中介紹了兩種佇列鎖,一種是有界佇列鎖,一種是無界佇列鎖。其中無界佇列鎖CLHLock採用了連結串列的方式來組織多執行緒,使用了兩個ThreadLocal做指標指向自身的node和前一個node。它的特點是在前一個node的lock

搶佔式核心與非搶佔式核心中的spinlock的區別

一、概括 (1)自旋鎖適用於SMP系統,UP系統用spinlock是作死。 (2)保護模式下禁止核心搶佔的方法:1、執行終端服務例程時2、執行軟中斷和tasklet時3、設定本地CPU計數器preempt_count (3)自旋鎖的忙等待的實際意義是:嘗試獲取自旋鎖的另一個

聊聊高併發實現幾種

在聊聊高併發(五)理解快取一致性協議以及對併發程式設計的影響 我們瞭解了處理器快取一致性協議的原理,並且提到了它對併發程式設計的影響,“多個執行緒對同一個變數一直使用CAS操作,那麼會有大量修改操作,從而產生大量的快取一致性流量,因為每一次CAS操作都會發出廣播通知其他處理

java 可重入且無死

java自旋鎖 的實現原理:如果自旋鎖被另外一個執行緒物件持有,那麼當前獲取鎖的執行緒將陷入while迴圈等待,直到那個持有自旋鎖的執行緒物件釋放它所持有的自旋鎖,那麼那些想要獲取該自旋鎖的執行緒物件 將會有一個獲得該自旋鎖。   基於他這種原理,等待的時候,並不釋放cpu

Nginx學習之四-Nginx程序同步方式-spinlock

自旋鎖簡介 Nginx框架使用了三種訊息傳遞方式:共享記憶體、套接字、訊號。 Nginx主要使用了三種同步方式:原子操作、訊號量、檔案鎖。 基於原子操作,nginx實現了一個自旋鎖。自旋鎖是一種非睡眠鎖。如果某程序檢視獲得自旋鎖,當發現鎖已經被其他程序獲得時,那麼不會使得

[轉]排隊、MCS、CLH

自旋鎖(Spin lock) 自旋鎖是指當一個執行緒嘗試獲取某個鎖時,如果該鎖已被其他執行緒佔用,就一直迴圈檢測鎖是否被釋放,而不是進入執行緒掛起或睡眠狀態。 自旋鎖適用於鎖保護的臨界區很小的情況,臨界區很小的話,鎖佔用的時間就很短。 簡單的實現 import java.util.concurren

-SpinLock.NET 4.0+

參考:https://www.cnblogs.com/1zhk/p/5269722.html  和 https://www.cnblogs.com/chenwolong/archive/2017/05/18/6872672.html Parallel.ForEach 和 ForEach

偏向、輕量級、重量級膨脹消除、粗化

知識準備: 在開始前,首先清楚系統PV訊號機制 荷蘭學者Dijkstra於1965年提出的訊號機制是一種有效的程序同步與互斥工具。 1)整型訊號與PV操作 訊號量是一個整型變數,根據控制物件的不同被賦予不同的值。訊號量分為如下兩類: (1)公用訊號量。實現程序間的互

Java的種類以及辨析的其他種類

作者:山雞 鎖作為併發共享資料,保證一致性的工具,在JAVA平臺有多種實現(如 synchronized 和 ReentrantLock等等 ) 。這些已經寫好提供的鎖為我們開發提供了便利,但是鎖的具體性質以及型別卻很少被提及。本系列文章將分析JAVA下常見的鎖名稱以及特性,為大家答疑解惑。

java的種類以及辨析

作者:山雞 鎖作為併發共享資料,保證一致性的工具,在JAVA平臺有多種實現(如 synchronized 和 ReentrantLock等等 ) 。這些已經寫好提供的鎖為我們開發提供了便利,但是鎖的具體性質以及型別卻很少被提及。本系列文章將分析JAVA下常見的鎖名稱以及特性,為大家答疑解惑。

1.6的優化適應性/粗化/削除/輕量級/偏向

     高效併發是JDK 1.6的一個重要主題,HotSpot虛擬機器開發團隊在這個版本上花費了大量的精力去實現各種鎖優化技術,如適應性自旋(Adaptive Spinning)、鎖削除(Lock Elimination)、鎖膨脹(Lock Coarsening)、輕量級

java同步優化方案學習筆記偏向,輕量級,重量級

目錄 一,概述 二,CAS 一,概述 什麼是java的鎖? 為什麼java要有鎖? java的鎖為什麼需要優化? 怎麼優化的? 1,java中使用synchronized關鍵字來實現同步功能,被synchronized修飾的方法

多執行緒的那點兒事

【 宣告:版權所有,歡迎轉載,請勿用於商業用途。  聯絡信箱:feixiaoxing @163.com】    自旋鎖是SMP中經常使用到的一個鎖。所謂的smp,就是對稱多處理器的意思。在工業用的pcb板上面,特別是伺服器上面,一個pcb板有多個cpu是很正常的事情。這些c

Java併發包原始碼學習之AQS框架CLH lock queue和

上一篇文章提到AQS是基於CLH lock queue,那麼什麼是CLH lock queue,說複雜很複雜說簡單也簡單, 所謂大道至簡: CLH lock queue其實就是一個FIFO的佇列,佇列中的每個結點(執行緒)只要等待其前繼釋放鎖就可以了。 AbstractQueuedSynchronizer

Java併發框架——AQS阻塞佇列管理——

我們知道一個執行緒在嘗試獲取鎖失敗後將被阻塞並加入等待佇列中,它是一個怎樣的佇列?又是如何管理此佇列?這節聊聊CHL Node FIFO佇列。 在談到CHL Node FIFO佇列之前,我們先分析這種佇列的幾個要素。首先要了解的是自旋鎖,所謂自旋鎖即是某一執行緒去嘗試獲取某個