In addition to Weibo, there is also WeChat
Please pay attention
WeChat public account
Shulou
2025-01-15 Update From: SLTechnology News&Howtos shulou NAV: SLTechnology News&Howtos > Development >
Share
Shulou(Shulou.com)06/03 Report--
This article mainly explains "how to understand Mutex in the Go runtime". The content in the article is simple and clear, and it is easy to learn and understand. Please follow the editor's train of thought to study and learn "how to understand Mutex in the Go runtime".
Sync.Mutex is a high level synchronization primitive, is a data structure for the majority of Go developers to develop applications, and now its internal implementation logic is more complex, including spin and hunger handling logic, its underlying use of some functions of the runtime low level and some methods of atomic.
Mutex in the runtime is a synchronization primitive for the internal use of mutexes at run time, it provides spin and wait queues, does not address hunger, and its implementation is different from that of sync.Mutex. Instead of providing Lock/Unlock as a method, it provides lock/unlock functions to implement the request lock and release the lock.
Dan Scales added static locking rank functionality to runtime locks at the beginning of this year. He defines rank for runtime architecture-independent locks (architecture-independent locks) and defines the partial order of some runtime locks (which locks are allowed to hold before this lock). This is a big change for runtime locks, but unfortunately there is no design document describing the design of this feature in detail. You can learn about the code changes in runtime internal locks through the submitted comment (# 0a820007) and comments in the code.
In essence, this function is used to check whether the order of the locks is executed in the order in which the document is designed, and if there is a violation of the set order, deadlocks may occur. Because of the lack of accurate documentation and the fact that this feature is mainly used to check the execution order of runtime locks, I will erase this logic in this article. To start this check at the actual Go runtime, you need to set the variable GOEXPERIMENT=staticlockranking.
So let's take a look at the definition of the data structure of the runtime mutex and the implementation of lock/unlock.
Runtime mutex data structure
The runtime mutex data structure is simple, as follows, defined in runtime2.go:
Type mutex struct {lockRankStruct / / Futex-based impl treats it as uint32 key, / / while sema-based impl as M * waitm. / / Used to be a union, but unions break precise GC. Key uintptr}
If lock ranking is not enabled, lockRankStruct is actually an empty structure:
Type lockRankStruct struct {}
So for the runtime mutex, the most important thing is the key field. This field has different meanings for different architectures.
For dragonfly, freebsd, and linux architectures, mutex uses a Futex-based implementation, and key is a value of uint32. The Futex (Fast user-space mutexes) provided by Linux is used to build locks and semaphores in user space. The Go runtime encapsulates two methods to sleep and wake up the current thread:
Futexsleep (addr uint32, val uint32, ns int64): atomic operation`if addr = = val {sleep} `.
Futexwakeup (addr * uint32, cnt uint32): wake up threads at the address addr up to cnt times.
For other architectures, such as aix, darwin, netbsd, openbsd, plan9, solaris, and windows,mutex, sema-based implementations are used, and key is M * waitm. The Go runtime encapsulates three methods for creating semaphores and sleep/wakeup:
Func semacreate (mp * m): create semaphore
Func semasleep (ns int64) int32: request semaphore. If the request is not reached, it will sleep for a while.
Func semawakeup (mp * m): wake up mp
Based on these two implementations, there are different implementations of lock and unlock methods, and the main logic is similar, so let's just look at Futex-based lock/unlock.
Request lock lock
If you do not use the lock ranking feature, the logic of lock is mainly implemented by lock2.
Func lock (l * mutex) {lockWithRank (l, getLockRank (l))} func lockWithRank (l * mutex, rank lockRank) {lock2 (l)} func lock2 (l * mutex) {/ / get g object gp: = getg () / g bound m object lock count plus 1 if gp.m.locks
< 0 { throw("runtime·lock: lock count") } gp.m.locks++ // 如果有幸运光环,原来锁没有被持有,一把就获取到了锁,就快速返回了 v := atomic.Xchg(key32(&l.key), mutex_locked) if v == mutex_unlocked { return } // 否则原来的可能是MUTEX_LOCKED或者MUTEX_SLEEPING wait := v // 单核不进行spin,多核CPU情况下会尝试spin spin := 0 if ncpu >1 {spin = active_spin} for {/ / try spin. If the lock has been released, try to grab the lock I: = 0; I < spin If atomic.Cas + {for l.key = = mutex_unlocked {if atomic.Cas (& l.key), mutex_unlocked, wait) {return}} / / PAUSE procyield (active_spin_cnt)} / / try to grab the lock again, rescheduling. For I: = 0; I < passive_spin ILock + {for l.key = = mutex_unlocked {if atomic.Cas (key32 (& l.key), mutex_unlocked, wait) {return}} osyield ()} / / try to grab the lock again, and set key to mutex_sleeping. If the lock is successful Return v = atomic.Xchg (key32 (& l.key), mutex_sleeping) if v = = mutex_unlocked {return} / / otherwise sleep waits for wait = mutex_sleeping futexsleep (& l.key), mutex_sleeping,-1)}}
Unlock
If you do not use the lock ranking feature, the logic of unlock is mainly implemented by unlock2.
Func unlock (l * mutex) {unlockWithRank (l)} func unlockWithRank (l * mutex) {unlock2 (l)} func unlock2 (l * mutex) {/ / set the value of key to mutex_unlocked v: = atomic.Xchg (key32 (& l.key), mutex_unlocked) if v = = mutex_unlocked {throw ("unlock of unlocked lock")} / / if there is a thread in sleep Wake it up if v = = mutex_sleeping {futexwakeup (key32 (& l.key), 1)} / / to get the current goroutine and the m associated with it Subtract 1 gp: = getg () gp.m.locks-- if gp.m.locks < 0 {throw ("runtime ·unlock: lock count")} if gp.m.locks = = 0 & & gp.preempt {/ / restore the preemption request in case we've cleared it in newstack gp.stackguard0 = stackPreempt}}
Overall, the runtime mutex logic is not too complex, mainly to deal with the implementation of different architectures, it hibernates and wakes up the object is m, while the sync.Mutex hibernating wakes up the object is g.
Thank you for your reading, the above is the content of "how to understand Mutex in Go runtime". After the study of this article, I believe you have a deeper understanding of how to understand Mutex in Go runtime, and the specific use needs to be verified in practice. Here is, the editor will push for you more related knowledge points of the article, welcome to follow!
Welcome to subscribe "Shulou Technology Information " to get latest news, interesting things and hot topics in the IT industry, and controls the hottest and latest Internet news, technology news and IT industry trends.
Views: 0
*The comments in the above article only represent the author's personal views and do not represent the views and positions of this website. If you have more insights, please feel free to contribute and share.
Continue with the installation of the previous hadoop.First, install zookooper1. Decompress zookoope
"Every 5-10 years, there's a rare product, a really special, very unusual product that's the most un
© 2024 shulou.com SLNews company. All rights reserved.