[Golang]同步工具-sync包的Cond-心智图总结

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也是。

https://ithelp.ithome.com.tw/upload/images/20201120/20131728gfW5BXgqnB.png

参考来源:
郝林-Go语言核心36讲
https://github.com/hyper0x/Golang_Puzzlers
https://golang.org/pkg/cmd/go/internal/test/


<<:  【资料结构】前後序求值

>>:  ASP.NET Core 3 起布置在 Windows IIS 方式改变

Day19 - 登入token与session相关问题

tags: 2021永丰金铁人赛 初学者在使用的时候,可能会遇到下列错误讯息: File "...

Day09 Kibana - Query DSL 复合查询

这一个章节节我们要来介绍复合查询,当单一的查询子句无法完成需求时,为了应付这种高级查询需求,所以就产...

【Day 3】机器学习基本功(一)

机器学习三大步骤 定义一个模型(model) 从模型里挑出好的函式(function) 经由演算法找...

Vue CLI安装

前面都使引用CDN的script标签去使用Vue.js,今天要介绍的是用NPM去安装vue-cli ...

Golang 切片slice与Map

Golang 切片(Slice) 我看很多中文的教学都是翻切片,我也不知道是不是正确的说法,总之也附...