Zwlin's Blog

[笔记] Go sync.Cond

2020/10/22

Concept

Cond implements a condition variable, a rendezvous point for goroutines waiting for or announcing the occurrence of an event.

Each Cond has an associated Locker L (often a *Mutex or *RWMutex), which must be held when changing the condition and when calling the Wait method.

A Cond must not be copied after first use.

条件变量并不是被用来保护临界区和共享资源的,它是用于协调想要访问共享资源的那些线程的。当共享资源的状态发生变化时,它可以被用来通知被互斥锁阻塞的线程。

Methods

func NewCond

1func NewCond(l Locker) *Cond

NewCond returns a new Cond with Locker l.

func (*Cond) Broadcast

1func (c *Cond) Broadcast()

Broadcast wakes all goroutines waiting on c.

It is allowed but not required for the caller to hold c.L during the call.

func (*Cond) Signal

1func (c *Cond) Signal()

Signal wakes one goroutine waiting on c, if there is any.

It is allowed but not required for the caller to hold c.L during the call.

func (*Cond) Wait

1func (c *Cond) Wait()

Wait atomically unlocks c.L and suspends execution of the calling goroutine. After later resuming execution, Wait locks c.L before returning. Unlike in other systems, Wait cannot return unless awoken by Broadcast or Signal.

Because c.L is not locked when Wait first resumes, the caller typically cannot assume that the condition is true when Wait returns. Instead, the caller should Wait in a loop:

1c.L.Lock()
2for !condition() {
3    c.Wait()
4}
5... make use of condition ...
6c.L.Unlock()

Example

 1package main
 2
 3import (
 4	"log"
 5	"sync"
 6	"time"
 7)
 8
 9func main() {
10	var mailbox uint8
11
12	var lock sync.RWMutex
13
14	sendCond := sync.NewCond(&lock)
15	recvCond := sync.NewCond(lock.RLocker())
16
17	var wg sync.WaitGroup
18
19	wg.Add(2)
20	max := 5
21	go func(max int) {
22		defer wg.Done()
23
24		for i:=1;i<=max;i++{
25			time.Sleep(500*time.Millisecond)
26			lock.Lock()
27			for mailbox ==1 {
28				sendCond.Wait()
29			}
30			log.Printf("sender [%d]: the mailbox is empty.",i)
31			mailbox =1
32			log.Printf("sender [%d]: the letter has been sent.", i)
33			lock.Unlock()
34			recvCond.Signal()
35		}
36	}(max)
37
38	go func(max int) {
39		defer wg.Done()
40
41		for j:=1;j<=max;j++{
42			time.Sleep(500*time.Millisecond)
43			lock.RLock()
44			for mailbox == 0{
45				recvCond.Wait()
46			}
47			log.Printf("receiver [%d]: the mailbox is full.", j)
48			mailbox = 0
49			log.Printf("receiver [%d]: the letter has been received.", j)
50			lock.RUnlock()
51			sendCond.Signal()
52		}
53	}(max)
54
55	wg.Wait()
56}

Explanation

条件变量的Wait方法主要做了四件事。

References