golang 自旋鎖的實現

2022-09-24 14:48:17 字數 2310 閱讀 1166

cas演算法(compare and swap)

cas演算法是一種有名的無鎖演算法。無鎖程式設計,即不使用鎖的情況下實現多執行緒之間的變數同步,也就是在沒有執行緒被阻塞的情況下實現變數的同步,所以也叫非阻塞同步(non-blocking synchronization)。cas演算法涉及到三個運算元

當且僅當 v 的值等於 a時,cas通過原子方式用新值b來更新v的值,否則不會執行任何操作(比較和替換是乙個原子操作)。一般情況下是乙個自旋操作,即不斷的重試。

自旋鎖自旋鎖是指當乙個執行緒在獲取鎖的時候,如果鎖已經被其他執行緒獲取,那麼該執行緒將迴圈等待,然後不斷地判斷是否能夠被成功獲取,知直到獲取到鎖才會退出迴圈。

獲取鎖的執行緒一直處於活躍狀態,但是並沒有執行任何有效的任務,使用這種鎖會造成 busy-waiting 。

它是為實現保護共享資源而提出的一種鎖機制。其實,自旋鎖與互斥鎖比較類似,它們都是為了解決某項資源的互斥使用。無論是互斥鎖,還是自旋鎖,在任何時刻,最多只能由乙個保持者,也就說,在任何時刻最多只能有乙個執行單元獲得鎖。但是兩者在排程機制上略有不同。對於互斥鎖,如果資源已經被占用,資源申請者只能進入睡眠狀態。但是自旋鎖不會引起呼叫者睡眠,如果自旋鎖已經被別的執行單元保持,呼叫者就一直迴圈在那裡看是否該自旋鎖的保持者已經釋放了鎖,「自旋」一詞就是因此而得名。

golang實現自旋鎖

type spinlock uint32

func (sl *spinlock) lock()

}func (sl *spinlock) unlock()

func newspinlock() sync.locker

可重入的自旋鎖和不可重入的自旋鎖

文章開始的時候的那段**,仔細分析一下就可以看出,它是不支援重入的,即當乙個執行緒第一次已經獲取到了該鎖,在鎖釋放之前又一次重新獲取該鎖,第二次就不能成功獲取到。由於不滿足cas,所以第二次獲取會進入while迴圈等待,而如果是可重入鎖,第二次也是應該能夠成功獲取到程式設計客棧的。

而且,即使第二次能夠成功獲取,那麼當第一次釋放鎖的時候,第二次獲取到的鎖也會被釋放,而這是不合理的。

為了實現可重入鎖,我們需要引入乙個計數器,用來記錄獲取鎖的執行緒數

type spinlock struct

func (sl *spinlock) lock()

// 如果沒獲取到鎖,則通過cas自旋

for !atomic.compareandswapuint32((*uint32)(sl), 0, 1)

}func (sl *spinlock) unlock()

if sl.count >0 else

}func getgoroutineid() int

}()var buf [64]byte

n := runtime.stack(buf[:], false)

idfield := strings.fields(strings.trimprefix(string(buf[:n]), "goroutine "))[0]

id, err := strconv.atoi(idfield)

if err != nil

return id

}func newspinlock() sync.locker

自旋鎖的其他變種

1. ticketlock

ticketlock主要解決的是公平性的問題。

思路:每當有執行緒獲取鎖的時候,就給該執行緒分配乙個遞增的id,我們稱之為排隊號,同時,鎖對應乙個服務號,每當有執行緒釋放鎖,服務號就會遞增,此時如果服務號與某個執行緒排隊號一致,那麼該執行緒就獲得鎖,由於排隊號是遞增的,所以就保證了最先請求獲取鎖的執行緒可以最先獲取到鎖,就實現了公平性。

可以想象成銀行辦理業務排隊,排隊的每乙個顧客都代表乙個需要請求鎖的執行緒,而銀行服務視窗表示鎖,每當有視窗服務完成就把自己的服務號加一,此時在排隊的所有顧客中,只有自己的排隊號與服務號一致的才可以得到服務。

2. clhlock

clh鎖是一種基於鍊錶的可擴充套件、高效能、公平的自旋鎖,申請執行緒只在本地變數上自旋,它不斷輪詢前驅的狀態,如果發現前驅釋放了鎖就結束自旋,獲得鎖。

3. mcslock

mcslock則是對本地變數的節點進行迴圈。

4. clhlock 和 mcslock

都是基於鍊錶,不同的是clhlock是基於隱式鍊錶,沒有真正的後續節點屬性,mcslock是顯示鍊錶,有乙個指向後續節點的屬性。

將獲取鎖的執行緒狀態借助節點(node)儲存,每個執行緒都有乙份獨立的節點,這樣就解決了ticketlock多處理器快取同步的問題。

自旋鎖與互斥鎖

總結:本文標題: golang 自旋鎖的實現

本文位址: /jiaoben/golang/245559.html

C 自旋鎖簡單實現

c 11 版不帶自旋鎖的api,我們可以手動實現,有的時候執行緒執行的功能比較簡單,或者說 量較少,如果使用mutex的話,開銷比較大,但是使用mutex的鎖,執行緒處於非執行態時不占用cpu,這是其他的執行緒可以執行,使用自旋鎖時執行緒被阻塞,但是被阻塞執行緒依然不會讓出cpu,而是會不斷的whi...

Linux自旋鎖和互斥鎖的實現

自旋鎖 spin lock 應用在多處理器環境中。如果核心控制路徑發現自旋鎖 開著 就獲取鎖並繼續自己的執行。相反,如果核心控制路徑發現鎖由執行在另乙個cpu上的核心控制路徑 鎖 著 就在周圍 旋轉 反覆執行一條緊湊的迴圈指令,直到鎖被釋放。自旋鎖的迴圈指令表示 忙等 即使等待的核心控制路徑無事可做...

自旋鎖以及可重入自旋鎖

首先是簡單的自旋鎖 實現 package org.cc.concur public class mylock private boolean islocked false public synchronized void lock throws interruptedexception islock...