ZBLOG

golang Mutex 的源码

好的,以下是 Golang Mutex 的源代码:

type Mutex struct {
    state int32
    sema  uint32
}

func (m *Mutex) Lock() {
    // Fast path: 幸运的情况下,第一次就成功获取锁。
    if atomic.CompareAndSwapInt32(&m.state, 0, mutexLocked) {
        return
    }
    var waitStartTime int64
    starving := false
    awoke := false
    iter := 0
    old := m.state
repeat:
    for {
        // 如果互斥锁目前未被锁定,则尝试获取它。
        if old&mutexLocked == 0 {
            new := old | mutexLocked // 设置为已加锁状态。
            if atomic.CompareAndSwapInt32(&m.state, old, new) {
                if starving {
                    m.sema = 0 // 唤醒任何潜在的阻塞器。
                }
                return
            }
        }

        var delta int64 = -1

        // 如果当前不处于 hysteresis 模式,并且等待持续时间较长,则进入 hysteresis 模式,
        // 这样可以避免与其他 goroutine 发生竞争并使得所有 goroutines 都自旋等待.
        if !starving && runtime_canSpin(iter) { 
            iter++
            continue 
        } else if waitStartTime == 0 { 
            waitStartTime = runtime_nanotime() 
        } else if !starving && runtime_nanotime()-waitStartTime > starvationThresholdNs && atomic.CompareAndSwapUint32(&m.sema, 0, mutexLocked-1) { 
            // 如果等待的时间太长,则将锁置于饥饿状态,并创建一个阻塞器。
            starving = true 
            runtime_SemacquireMutex(&m.sema, false, 1)
            waitStartTime = runtime_nanotime()
            awoke = true
        } else { // 如果需要等待,则自旋等待获取锁。
            if delta < 0 {
                delta = runtime_nanotime()
            }
            runtime_doSpin()
        }

        old = m.state

        // 如果当前 goroutine 在 hysteresis 模式下(自旋),则重试并稍微增加 spin 的速度。
        if old&mutexLocked != 0 && (!starving || (runtime_nanotime()-waitStartTime)&busyWaitInterval == 0) { 
            iter++
            runtime_doSpin()
        }

    }

}

func (m *Mutex) Unlock() {
    if atomic.LoadInt32(&m.state) == 0 {
        panic("sync: unlock of unlocked mutex")
    }
    atomic.StoreInt32(&m.state, 0)
    if m.sema > 0 {
        runtime_Semrelease(&m.sema, false, 1)
    }
}

这里是一些关键点:

  • Mutex 是一个结构体,它具有两个字段:state 和 sema。state 表示互斥锁是否被锁定,sema 表示当前有多少个 goroutine 在等待互斥锁。
  • Lock() 方法尝试获取互斥锁。如果该互斥锁已经被其他 goroutine 锁定,则它会进入一个 for 循环,自旋等待直到可以获得互斥锁。如果 goroutine 在循环中持续自旋等待的时间过长,它将进入 hysteresis 模式,并阻塞等待互斥锁可用。
  • Unlock() 方法用于释放互斥锁。如果该互斥锁未被锁定,则会抛出 panic。如果有其他 goroutine 正在等待这个互斥锁,则它们将被唤醒并尝试获取该互斥锁。

总的来说,Golang Mutex 的实现使用了多种技术(如自旋、hysteresis 等)以优化性能和减少竞争,使其成为一个非常高效且线程安全的同步机制。

本站部分文章来源于网络,版权归原作者所有,如有侵权请联系站长删除。
转载请注明出处:https://golang.0voice.com/?id=3444

分享:
扫描分享到社交APP
上一篇
下一篇
发表列表
游客 游客
此处应有掌声~
评论列表

还没有评论,快来说点什么吧~

联系我们

在线咨询: 点击这里给我发消息

微信号:3007537140

上班时间: 10:30-22:30

关注我们
x

注册

已经有帐号?