77 lines
2.1 KiB
Markdown
77 lines
2.1 KiB
Markdown
### sync 包低级同步原语使用场景
|
||
- 高性能的临界区(critical section)同步机制场景
|
||
- 不想转移结构体对象所有权,但又要保证结构体内部状态数据的同步访问的场景
|
||
|
||
### sync包原语使用注意事项
|
||
- 不要将原语复制后使用
|
||
- 用闭包或者传递原语变量的地址(指针)
|
||
|
||
### mutex 互斥锁
|
||
- 零值可用,不用初始化
|
||
- Lock,Unlock
|
||
- lock状态下任何goroutine加锁都会阻塞
|
||
|
||
### RWMutex 读写锁
|
||
- 零值可用,不用初始化
|
||
- RLock,RUnlock 加读锁,解读锁
|
||
- Lock,Unlock 加写锁,解写锁
|
||
- 加读锁状态下,不会阻塞加读锁,会阻塞加写锁
|
||
- 加写锁状态下,会阻塞加读锁与写锁的goroutine
|
||
|
||
### sync.Cond 条件变量
|
||
- sync.Cond是传统的条件变量原语概念在 Go 语言中的实现
|
||
- 可以把一个条件变量理解为一个容器,这个容器中存放着一个或一组等待着某个条件成立的 Goroutine
|
||
- 当条件成立后,处于等待状态的 Goroutine 将得到通知,并被唤醒继续进行后续的工作
|
||
```go
|
||
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!")
|
||
}
|
||
``` |