sync

sync #

  • sync.Mutex
  • sync.RWMutex
  • sync.WaitGroup
  • sync.Once
  • sync.Cond

锁的类型 #

Mutex 互斥锁 #

type Mutex struct {
	state int32
	sema  uint32 // semaphore 信号量
}
  • sync.Mutex.Lock 和 sync.Mutex.Unlock

state #

# 8 位
**** ****

*****               *              *           *
waitersCount  mutexStarving   mutexWoken   mutexLocked
  • mutexLocked — 表示互斥锁的锁定状态
  • mutexWoken — 表示从正常模式被从唤醒
  • mutexStarving — 当前的互斥锁进入饥饿状态
    • Goroutine 超过 1ms 没有获取到锁,它就会将当前互斥锁切换饥饿模式,防止被饿死,造成高尾延时
  • waitersCount — 当前互斥锁上等待的 Goroutine 个数 (最多 128 个)

RWMutex #

type RWMutex struct {
	w           Mutex
	writerSem   uint32
	readerSem   uint32
	readerCount int32
	readerWait  int32
}
  • 写操作使用 sync.RWMutex.Lock 和 sync.RWMutex.Unlock 方法;
  • 读操作使用 sync.RWMutex.RLock 和 sync.RWMutex.RUnlock 方法;

  • 调用 sync.RWMutex.Lock 尝试获取写锁时;
    • 每次 sync.RWMutex.RUnlock 都会将 readerWait 其减一,当它归零时该 Goroutine 就会获得写锁;
    • 将 readerCount 减少 rwmutexMaxReaders 个数以阻塞后续的读操作;
  • 调用 sync.RWMutex.Unlock 释放写锁时,会先通知所有的读操作,然后才会释放持有的互斥锁;

读写互斥锁在互斥锁之上提供了额外的更细粒度的控制,能够在读操作远远多于写操作时提升性能。


WaitGroup #

type WaitGroup struct {
	noCopy noCopy // wg 无法复制
	state1 [3]uint32
}

requests := []*Request{...}
wg := &sync.WaitGroup{}
wg.Add(len(requests))

for _, request := range requests {
    go func(r *Request) {
        defer wg.Done()
        // res, err := service.call(r)
    }(request)
}
wg.Wait()

Done #

sync.WaitGroup.Done 只是对 sync.WaitGroup.Add 方法的简单封装, 我们可以向 sync.WaitGroup.Add 方法传入任意负数(需要保证计数器非负)快速将计数器归零以唤醒其他等待的 Goroutine;


Once #

  • sync.Once.Do 方法中传入的函数只会被执行一次,哪怕函数中发生了 panic
  • 两次调用 sync.Once.Do 方法传入不同的函数也只会执行第一次调用的函数;
type Once struct {
	done uint32
	m    Mutex
}

Cond #

type Cond struct {
	L       Locker // 用于保护内部的 notify 字段
	notify  notifyList
	noCopy  noCopy // 保证结构体不会在编译期间拷贝
	checker copyChecker // 禁止运行期间发生的拷贝
}

type notifyList struct {
	wait uint32
	notify uint32

	lock mutex
	head *sudog
	tail *sudog
}

  • sync.Cond.Wait 将当前 Goroutine 陷入休眠状态
    • 在调用之前一定要使用获取互斥锁,否则会触发程序崩溃
  • sync.Cond.Signal 唤醒队列最前面的 Goroutine
  • sync.Cond.Broadcast 唤醒队列中全部的 Goroutine