typora/note/Go/sync包.md
2024-12-12 10:48:55 +08:00

2.1 KiB
Raw Permalink Blame History

sync 包低级同步原语使用场景

  • 高性能的临界区critical section同步机制场景
  • 不想转移结构体对象所有权,但又要保证结构体内部状态数据的同步访问的场景

sync包原语使用注意事项

  • 不要将原语复制后使用
  • 用闭包或者传递原语变量的地址(指针)

mutex 互斥锁

  • 零值可用,不用初始化
  • LockUnlock
  • lock状态下任何goroutine加锁都会阻塞

RWMutex 读写锁

  • 零值可用,不用初始化
  • RLockRUnlock 加读锁,解读锁
  • LockUnlock 加写锁,解写锁
  • 加读锁状态下,不会阻塞加读锁,会阻塞加写锁
  • 加写锁状态下会阻塞加读锁与写锁的goroutine

sync.Cond 条件变量

  • sync.Cond是传统的条件变量原语概念在 Go 语言中的实现
  • 可以把一个条件变量理解为一个容器,这个容器中存放着一个或一组等待着某个条件成立的 Goroutine
  • 当条件成立后,处于等待状态的 Goroutine 将得到通知,并被唤醒继续进行后续的工作
type signal struct{}

var ready bool

func worker(i int) {
  fmt.Printf("worker %d: is working...\n", i)
  time.Sleep(1 * time.Second)
  fmt.Printf("worker %d: works done\n", i)
}

func spawnGroup(f func(i int), num int, groupSignal *sync.Cond) <-chan signal {
  c := make(chan signal)
  var wg sync.WaitGroup

  for i := 0; i < num; i++ {
    wg.Add(1)
    go func(i int) {
      groupSignal.L.Lock()
      for !ready {
        groupSignal.Wait()
      }
      groupSignal.L.Unlock()
      fmt.Printf("worker %d: start to work...\n", i)
      f(i)
      wg.Done()
    }(i + 1)
  }

  go func() {
    wg.Wait()
    c <- signal(struct{}{})
  }()
  return c
}

func main() {
  fmt.Println("start a group of workers...")
  groupSignal := sync.NewCond(&sync.Mutex{})
  c := spawnGroup(worker, 5, groupSignal)

  time.Sleep(5 * time.Second) // 模拟ready前的准备工作
  fmt.Println("the group of workers start to work...")

  groupSignal.L.Lock()
  ready = true
  groupSignal.Broadcast()
  groupSignal.L.Unlock()

  <-c
  fmt.Println("the group of workers work done!")
}