Go EP 15: sync.Mutex - Normal and Starvation Mode
Mutex, or MUTual EXclusion, in Go is basically a way to make sure that only one goroutine is messing with a shared resource at a time. This resource can be a piece of code, an integer, a map, a struct
In this week, I'll post key points and takeaways from my latest articles: Golang Sync Mutex: Normal and Starvation Mode.
If you're interested in diving deeper into the content, you can follow the links provided to read the full posts.
The structure of a mutex is more complex than it appears. Its 'state' field is a 32-bit integer that cleverly encodes multiple pieces of information about the mutex's current status, including whether it's locked, if a goroutine has been woken up, if it's in starvation mode, and how many goroutines are waiting.
Mutex locking has both a fast path and a slow path. The fast path is designed for quick lock acquisition when the mutex isn't in use, and it's inlined for better performance. The slow path handles more complex scenarios, including spinning and waiting.
Spinning is an optimization technique used in the mutex's slow path. Before a goroutine gives up and goes to sleep, it actively tries to acquire the lock for up to 120 CPU cycles. This can be more efficient than immediately going to sleep, especially if the lock becomes available quickly.
TEXT runtime·procyield(SB),NOSPLIT,$0-0
MOVWU cycles+0(FP), R0
again:
YIELD
SUBW $1, R0
CBNZ R0, again
RET
Go's mutex has two modes: normal mode and starvation mode. Starvation mode is an interesting feature that kicks in if a goroutine fails to acquire the lock for more than 1 millisecond. It ensures fairness by directly passing control to waiting goroutines, preventing new goroutines from unfairly acquiring the lock.
The unlock process also has a fast path and a slow path. The slow path behaves differently depending on whether the mutex is in normal or starvation mode. In starvation mode, it directly hands off ownership to the next waiting goroutine, ensuring fair access to the mutex.