1. sync包的Cond,提供条件变数。
a. 条件变数是基於互斥锁的,它必须有互斥锁的支撑,才能使用。
b. 条件变数并不是被用来保护共享资源,它是用来协调想要访问共享资源的那些goroutines。
当共享资源的状态发生改变时,它可以被用来通知被互斥锁阻塞的goroutine。
c. 函数:
func NewCond(l Locker) *Cond
func (c *Cond) Broadcast()
func (c *Cond) Signal()
func (c *Cond) Wait()
func (rw *RWMutex) Lock()
func (rw *RWMutex) Unlock()
func (rw *RWMutex) RLock()
func (rw *RWMutex) RUnlock()
2. 条件变数如何和读/写互斥锁一起使用?
参考范例:
package main
import (
"log"
"sync"
"time"
)
func main() {
// mailbox 代表信箱。
// 0代表信箱是空的,1代表信箱是满的。
var mailbox uint8
// lock 代表信箱上的锁。
var lock sync.RWMutex
// sendCond 代表专用於发信的条件变数。
sendCond := sync.NewCond(&lock)
// recvCond 代表专用於收信的条件变数。
recvCond := sync.NewCond(lock.RLocker())
// sign 用於传递演示完成的信号。
sign := make(chan struct{}, 3)
max := 5
go func(max int) { // 用於发信。
defer func() {
sign <- struct{}{}
}()
for i := 1; i <= max; i++ {
time.Sleep(time.Millisecond * 500)
lock.Lock()
for mailbox == 1 {
sendCond.Wait()
}
log.Printf("sender [%d]: the mailbox is empty.", i)
mailbox = 1
log.Printf("sender [%d]: the letter has been sent.", i)
lock.Unlock()
recvCond.Signal()
}
}(max)
go func(max int) { // 用於收信。
defer func() {
sign <- struct{}{}
}()
for j := 1; j <= max; j++ {
time.Sleep(time.Millisecond * 500)
lock.RLock()
for mailbox == 0 {
recvCond.Wait()
}
log.Printf("receiver [%d]: the mailbox is full.", j)
mailbox = 0
log.Printf("receiver [%d]: the letter has been received.", j)
lock.RUnlock()
sendCond.Signal()
}
}(max)
<-sign
<-sign
}
https://play.golang.org/p/qY4mLfzKSuG
3. 范例细节说明
a. 与sync.Mutex和sync.RWMutex类型不同,sync.Cond类型并不是开箱即用。
需要利用sync.NewCond函数创建它的指标值,而这个函数需要sync.Locker类型的参数值。
b. sendCond和recvCond都是属於*sync.Cond类型,同时使用sync.NewCond函数初始化。
sendCond := sync.NewCond(&lock)
recvCond := sync.NewCond(lock.RLocker())
sendCond变数在初始化时,要把lock的指标值传给sync.NewCond函数。
因为,sendCond专门用来对共享资源的写操作。lock变数的Lock和Unlock方法分别用於对写锁的锁定和解锁。
recvCond变数在初始化时,只要把RLocker的值传给sync.NewCond函数。
因为,recvCond只会对共享资源进行读操作。
c. 使用条件变数(sendCond、recvCond),实现单向通知(sendCond.Signal()、recvCond.Signal())。
sender的goroutine开始执行,会阻塞在sendCond.Wait()等待有人发送Signal(sendCond.Signal())。
当sender收到Signal後,就会继续往下执行。
而receiver也是。
参考来源:
郝林-Go语言核心36讲
https://github.com/hyper0x/Golang_Puzzlers
https://golang.org/pkg/cmd/go/internal/test/
>>: ASP.NET Core 3 起布置在 Windows IIS 方式改变
tags: 2021永丰金铁人赛 初学者在使用的时候,可能会遇到下列错误讯息: File "...
这一个章节节我们要来介绍复合查询,当单一的查询子句无法完成需求时,为了应付这种高级查询需求,所以就产...
机器学习三大步骤 定义一个模型(model) 从模型里挑出好的函式(function) 经由演算法找...
前面都使引用CDN的script标签去使用Vue.js,今天要介绍的是用NPM去安装vue-cli ...
Golang 切片(Slice) 我看很多中文的教学都是翻切片,我也不知道是不是正确的说法,总之也附...