go mutex互斥锁使用Lock和Unlock方法占有释放资源

  // Lock mutex 的锁方法。

  func (m *Mutex) Lock() {

  // 快速上锁.

  if atomic.CompareAndSwapInt32(&m.state, 0, mutexLocked) {

  if race.Enabled {

  race.Acquire(unsafe.Pointer(m))

  }

  return

  }

  // 快速上锁失败,将进行操作较多的上锁动作。

  m.lockSlow()

  }

  func (m *Mutex) lockSlow() {

  var waitStartTime int64 // 记录当前 goroutine 的等待时间

  starving := false // 是否饥饿

  awoke := false // 是否被唤醒

  iter := 0 // 自旋次数

  old := m.state // 当前 mutex 的状态

  for {

  // 当前 mutex 的状态已上锁,并且非饥饿模式,并且符合自旋条件

  if old&(mutexLocked|mutexStarving) == mutexLocked && runtime_canSpin(iter) {

  // 当前还没设置过唤醒标识

  if !awoke && old&mutexWoken == 0 && old>>mutexWaiterShift != 0 &&

  atomic.CompareAndSwapInt32(&m.state, old, old|mutexWoken) {

  awoke = true

  }

  runtime_doSpin()

  iter++

  old = m.state

  continue

  }

  new := old

  // 如果不是饥饿状态,则尝试上锁

  // 如果是饥饿状态,则不会上锁,因为当前的 goroutine 将会被阻塞并添加到等待唤起队列的队尾

  if old&mutexStarving == 0 {

  new |= mutexLocked

  }

  // 等待队列数量 + 1

  if old&(mutexLocked|mutexStarving) != 0 {

  new += 1 << mutexWaiterShift

  }

  // 如果 goroutine 之前是饥饿模式,则此次也设置为饥饿模式

  if starving && old&mutexLocked != 0 {

  new |= mutexStarving

  }

  //

  if awoke {

  // 如果状态不符合预期,则报错

  if new&mutexWoken == 0 {

  throw("sync: inconsistent mutex state")

  }

  // 新状态值需要清除唤醒标识,因为当前 goroutine 将会上锁或者再次 sleep

  new &^= mutexWoken

  }

  // CAS 尝试性修改状态,修改成功则表示获取到锁资源

  if atomic.CompareAndSwapInt32(&m.state, old, new) {

  // 非饥饿模式,并且未获取过锁,则说明此次的获取锁是 ok 的,直接 return

  if old&(mutexLocked|mutexStarving) == 0 {

  break

  }

  // 根据等待时间计算 queueLifo

  queueLifo := waitStartTime != 0

  if waitStartTime == 0 {

  waitStartTime = runtime_nanotime()

  }

  // 到这里,表示未能上锁成功

  // queueLife = true, 将会把 goroutine 放到等待队列队头

  // queueLife = false, 将会把 goroutine 放到等待队列队尾

  runtime_SemacquireMutex(&m.sema, queueLifo, 1)

  // 计算是否符合饥饿模式,即等待时间是否超过一定的时间

  starving = starving || runtime_nanotime()-waitStartTime > starvationThresholdNs

  old = m.state

  // 上一次是饥饿模式

  if old&mutexStarving != 0 {

  if old&(mutexLocked|mutexWoken) != 0 || old>>mutexWaiterShift == 0 {

  throw("sync: inconsistent mutex state")

  }

  delta := int32(mutexLocked - 1<

  // 此次不是饥饿模式又或者下次没有要唤起等待队列的 goroutine 了

  if !starving || old>>mutexWaiterShift == 1 {

  delta -= mutexStarving

  }

  atomic.AddInt32(&m.state, delta)

  break

  }

  // 此处已不再是饥饿模式了,清除自旋次数,重新到 for 循环竞争锁。

  awoke = true

  iter = 0

  } else {

  old = m.state

  }

  }

  if race.Enabled {

  race.Acquire(unsafe.Pointer(m))

  }

  }