新聞中心
在之前的設(shè)計(jì)中,當(dāng)鎖被占有,其他 goroutine 嘗試獲取鎖時(shí)會(huì)被阻塞。這種方式當(dāng)然是合理的,但是在某些情況下,或許我們希望在獲取鎖失敗時(shí),并不想停止執(zhí)行,而是可以進(jìn)入其他的邏輯。

創(chuàng)新互聯(lián)建站成立于2013年,我們提供高端成都網(wǎng)站建設(shè)、網(wǎng)站制作、成都網(wǎng)站設(shè)計(jì)、網(wǎng)站定制、全網(wǎng)營(yíng)銷推廣、小程序開(kāi)發(fā)、微信公眾號(hào)開(kāi)發(fā)、seo優(yōu)化排名服務(wù),提供專業(yè)營(yíng)銷思路、內(nèi)容策劃、視覺(jué)設(shè)計(jì)、程序開(kāi)發(fā)來(lái)完成項(xiàng)目落地,為成都房屋鑒定企業(yè)提供源源不斷的流量和訂單咨詢。
在 Go 1.18 中,為 sync.Mutex 新增了一個(gè)新的方法 TryLock(),它是一種非阻塞模式的取鎖操作。當(dāng)調(diào)用 TryLock() 時(shí),該函數(shù)僅簡(jiǎn)單地返回 true 或者 false,代表是否加鎖成功。
有了 TryLock 的存在,我們就可以由這樣的代碼:
m.Lock()
// 阻塞等待加鎖成功后的邏輯
轉(zhuǎn)變成這樣的邏輯
if m.TryLock(){
// 加鎖成功的邏輯
}else {
// 加鎖失敗的邏輯
}
TryLock 實(shí)現(xiàn)
在Go精妙的互斥鎖設(shè)計(jì)一文中,我們?cè)敿?xì)分析過(guò)互斥鎖的設(shè)計(jì),其代碼輕量簡(jiǎn)潔,通過(guò)巧妙的位運(yùn)算,僅僅采用 state 一個(gè)字段就實(shí)現(xiàn)了四個(gè)字段的效果,非常之精彩,建議感興趣的讀者一讀。
而 TryLock() 的實(shí)現(xiàn)更加簡(jiǎn)單。
func (m *Mutex) TryLock() bool {
old := m.state
if old&(mutexLocked|mutexStarving) != 0 {
return false
}
// There may be a goroutine waiting for the mutex, but we are
// running now and can try to grab the mutex before that
// goroutine wakes up.
if !atomic.CompareAndSwapInt32(&m.state, old, old|mutexLocked) {
return false
}
if race.Enabled {
race.Acquire(unsafe.Pointer(m))
}
return true
}
當(dāng)鎖被其他 goroutine 占有,或者當(dāng)前鎖正處于饑餓模式,它將立即返回 false。
func (m *Mutex) Lock() {
// Fast path: grab unlocked mutex.
if atomic.CompareAndSwapInt32(&m.state, 0, mutexLocked) {
if race.Enabled {
race.Acquire(unsafe.Pointer(m))
}
return
}
// Slow path (outlined so that the fast path can be inlined)
m.lockSlow()
}
而當(dāng)鎖可用時(shí),TryLock() 會(huì)采用與 Lock() 方法一樣的方式去嘗試獲取鎖。但在獲取失敗時(shí),與 Lock() 將不一樣,它不會(huì)自旋或者阻塞。這是一個(gè)完全的非阻塞獲取方式。
應(yīng)用場(chǎng)景
正如 TryLock() 方法的注釋一樣,它的應(yīng)用場(chǎng)景并不常見(jiàn),并且也不被鼓勵(lì)使用。
// Note that while correct uses of TryLock do exist, they are rare,
// and use of TryLock is often a sign of a deeper problem
// in a particular use of mutexes.
在當(dāng)前 Go1.18 標(biāo)準(zhǔn)庫(kù)源碼中,與 Lock() 方法被大量?jī)?nèi)部使用而截然不同的是,并沒(méi)有找到一處使用 TryLock() 的地方,僅僅在測(cè)試文件 mutex_test.go 中,有找到該方法的新增測(cè)試用例。
這里貼一個(gè) TryLock 的使用場(chǎng)景討論:https://stackoverflow.com/questions/41788074/use-case-for-lock-trylock
另外,在開(kāi)源社區(qū)已經(jīng)有不少 Go 的 TryLock 實(shí)現(xiàn)庫(kù)。它們基于 sync.Mutex 通過(guò) CAS 操作和 unsafe 指針實(shí)現(xiàn) ;或者利用 channel 實(shí)現(xiàn)。
但是這些庫(kù)都不能競(jìng)態(tài)檢測(cè)。因此,官方支持實(shí)現(xiàn) TryLock 是必要的,避免 TryLock 被濫用。且由于可以集成競(jìng)態(tài)檢測(cè),相較于三方庫(kù)實(shí)現(xiàn),有利于開(kāi)發(fā)者發(fā)現(xiàn)問(wèn)題。
總結(jié)
從 2012 年開(kāi)始,實(shí)際上很早就有關(guān)于 Go 增加 TryLock 的 issue 討論,但是直到 Go 1.18 才被增加。這其中很大一部分原因是,并沒(méi)有合理的案例值得添加 TryLock。
Go Team 的負(fù)責(zé)人 rsc 之前提出的反對(duì)意見(jiàn):TryLock 會(huì)鼓勵(lì)開(kāi)發(fā)者對(duì)鎖進(jìn)行不精確的思考,并最終導(dǎo)致競(jìng)態(tài)問(wèn)題。
另外,Go 1.18 除了為互斥鎖 sync.Mutex 新增了 TryLoc() 方法外,也為讀寫鎖 sync.RWMutex 新增了相應(yīng)的 TryRLock() 和 TryLock() 方法。
正如新增的這三個(gè)方法的注釋,雖然使用它們的情況存在,但很少見(jiàn),使用需謹(jǐn)慎。
名稱欄目:一篇學(xué)會(huì)Go的TryLock實(shí)現(xiàn)
分享路徑:http://m.5511xx.com/article/ccessis.html


咨詢
建站咨詢
