自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

Go 語言并發(fā)編程互斥鎖 sync.Mutex 底層實現(xiàn)

開發(fā) 前端
隨著 Go 語言版本迭代,sync.Mutex 的實現(xiàn)經(jīng)過高度優(yōu)化,能夠在低競爭和高競爭場景中提供高效的鎖定機(jī)制,同時盡量減少協(xié)程“饑餓”的情況。

1.介紹

本文通過閱讀 Go 語言 sync.Mutex 的源碼,我們一起學(xué)習(xí) sync.Mutex 的底層實現(xiàn)。

2.sync.Mutex` 源碼[1]分析

我們通過閱讀 Go 語言 sync.Mutex 的源碼,可以發(fā)現(xiàn) sync.Mutex 結(jié)構(gòu)體包含兩個字段:

type Mutex struct {
 state int32
 sema  uint32
}
  • state:存儲互斥鎖的狀態(tài)信息,包括鎖是否被占用、是否進(jìn)入饑餓模式,以及是否有協(xié)程被喚醒等。
  • sema:信號量,用于阻塞和喚醒等待該互斥鎖的協(xié)程。

state 字段

state 是一個 int32 類型的整數(shù),用來表示互斥鎖的當(dāng)前狀態(tài)。它并不是一個簡單的布爾值,而是通過多個位(bit)來記錄鎖的不同狀態(tài)。通過位運算,可以在同一個字段中存儲多種狀態(tài)信息。我們通過閱讀 lockSlow() 方法的源碼,可以發(fā)現(xiàn) state 包含的幾種狀態(tài)。

state 主要包含以下幾種狀態(tài):

const (
 mutexLocked = 1 << iota // mutex is locked
 mutexWoken
 mutexStarving
 mutexWaiterShift 
 starvationThresholdNs = 1e6
)
  • mutexLocker:表示互斥鎖是否已被鎖定。mutexLocked 是通過位移操作 1 << iota 定義的,當(dāng)其值為 1 時,表示互斥鎖已被鎖定。
  • mutexWoken:表示是否有等待的協(xié)程已被喚醒。這個狀態(tài)位防止多個等待的協(xié)程被同時喚醒,從而避免競爭鎖。
  • mutexStarving:表示互斥鎖是否處于饑餓模式。當(dāng)一個等待的協(xié)程長時間無法獲得鎖(超過 1 毫秒),互斥鎖會進(jìn)入饑餓模式,此時鎖的所有權(quán)會直接從釋放鎖的協(xié)程傳遞給等待隊列中的下一個協(xié)程。
  • mutexWaiterShift:表示有多少協(xié)程在等待獲取互斥鎖。通過將 state 字段右移來記錄當(dāng)前有多少協(xié)程處于等待狀態(tài)(每個等待的協(xié)程增加一個值)。

推薦讀者朋友們在項目開發(fā)中,多嘗試使用位運算。

此外,我們通過閱讀 lockSlow() 方法的源碼,發(fā)現(xiàn)其內(nèi)部實現(xiàn)中,使用“自旋鎖”和“CAS”,分別是 runtime_doSpin() 和 atomic.CompareAndSwapInt32()。

使用“自旋鎖”,當(dāng)互斥鎖可能很快被釋放時,協(xié)程可能會短暫地自旋等待,從而減少 CPU 上下文切換的開銷。

需要注意的是“自旋鎖”會占用 CPU 資源,我們在項目開發(fā)中使用時,切勿長時間進(jìn)行自旋等待。

使用“CAS”,用于對 state 變量進(jìn)行原子更新,確保線程安全。

sema 字段

sema 是一個 uint32 類型的信號量,用來控制阻塞和喚醒等待互斥鎖的協(xié)程。它通過與操作系統(tǒng)底層機(jī)制交互,負(fù)責(zé)在鎖被占用時阻塞協(xié)程,當(dāng)鎖被釋放時喚醒等待中的協(xié)程。

當(dāng)一個協(xié)程嘗試獲取鎖但鎖已被占用時,它需要進(jìn)入阻塞狀態(tài)。 sema 字段與 Go 的 runtime(運行時)機(jī)制合作,將這些等待的協(xié)程掛起。當(dāng)鎖被釋放時,runtime 會通過信號量來喚醒一個或多個等待的協(xié)程。

我們閱讀 lockSlow() 方法和 unlockSlow() 方法的源碼,可以發(fā)現(xiàn) sema 通過 runtime_SemacquireMutex() 和 runtime_Semrelease() 函數(shù)進(jìn)行操作。runtime_SemacquireMutex() 阻塞當(dāng)前協(xié)程并等待信號量,runtime_Semrelease() 則負(fù)責(zé)釋放信號量并喚醒等待的協(xié)程。

通過使用信號量,可以很好地處理高并發(fā)下的協(xié)程調(diào)度問題。與自旋鎖不同,信號量機(jī)制不會占用 CPU 資源。當(dāng)協(xié)程需要等待鎖時,它可以通過信號量進(jìn)入休眠,等待鎖釋放后再被喚醒,避免了忙等待帶來的性能損耗。

3.總結(jié)

本文我們通過閱讀 Go 語言 sync.Mutex 的源碼,更加深入了解 sync.Mutex 的底層實現(xiàn),它包含兩種操作模式,分別是:

普通模式:

在普通模式下,等待的協(xié)程按 FIFO 順序排隊,但新到達(dá)的協(xié)程可以和被喚醒的協(xié)程競爭鎖的所有權(quán),因為新協(xié)程已經(jīng)在 CPU 上運行,有一定的優(yōu)勢(即可以減少 CPU 上下文切換,從而提升性能)。如果一個協(xié)程等待超過 1 毫秒,互斥鎖會切換到饑餓模式。

饑餓模式:

當(dāng)協(xié)程等待超過 1 毫秒時,互斥鎖進(jìn)入饑餓模式。在饑餓模式下,新到達(dá)的協(xié)程不再直接嘗試獲取鎖,而是排隊等待。釋放鎖的協(xié)程會將鎖直接交給隊列中的第一個等待協(xié)程,從而避免長期等待的協(xié)程一直得不到鎖的情況。

state 字段通過位操作存儲了互斥鎖的多種狀態(tài),包括是否鎖定、是否進(jìn)入饑餓模式、等待隊列長度等,允許通過原子操作對這些狀態(tài)進(jìn)行高效的并發(fā)管理。

sema 字段是一個信號量,用于阻塞和喚醒等待鎖的協(xié)程,結(jié)合 Go runtime 的機(jī)制,實現(xiàn)高效的協(xié)程調(diào)度和喚醒。

這兩個字段共同構(gòu)成了 sync.Mutex 的核心,保證了在高并發(fā)場景下的互斥鎖操作既高效又安全。

隨著 Go 語言版本迭代,sync.Mutex 的實現(xiàn)經(jīng)過高度優(yōu)化,能夠在低競爭和高競爭場景中提供高效的鎖定機(jī)制,同時盡量減少協(xié)程“饑餓”的情況。

責(zé)任編輯:武曉燕 來源: Golang語言開發(fā)棧
相關(guān)推薦

2023-09-25 12:45:45

Go 語言可視化sync.Mute

2023-11-28 08:01:48

互斥鎖共享資源

2021-09-30 09:21:28

Go語言并發(fā)編程

2022-09-18 23:09:13

Go語言標(biāo)準(zhǔn)庫

2020-09-28 06:49:50

Linux系統(tǒng)編程互斥量mutex

2023-12-24 12:33:20

互斥鎖Go代碼

2023-06-02 08:29:24

https://wwMutex

2022-05-17 08:02:55

GoTryLock模式

2024-06-28 08:45:58

2023-02-10 09:40:36

Go語言并發(fā)

2021-03-22 11:27:06

C語言Peterson(皮特互斥鎖

2023-03-10 15:45:03

Golang公平鎖

2024-03-07 07:47:04

代碼塊Monitor

2021-03-24 08:02:58

C語言

2021-05-25 09:28:34

鴻蒙HarmonyOS應(yīng)用

2012-03-09 10:44:11

Java

2025-02-17 02:00:00

Monitor機(jī)制代碼

2020-08-26 08:59:58

Linux線程互斥鎖

2022-06-27 08:07:13

Go語言互斥鎖

2022-10-17 08:07:13

Go 語言并發(fā)編程
點贊
收藏

51CTO技術(shù)棧公眾號