TheRiver | blog

You have reached the world's edge, none but devils play past here

0%

golang sync.cond

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.

函数以及用法和unix的条件变量很相似。代码路径/usr/local/Cellar/go/1.15.2/libexec/src/sync/cond.go

struct

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
type Cond struct {
noCopy noCopy //禁止拷贝

// L is held while observing or changing the condition
L Locker

notify notifyList
checker copyChecker
}

// Approximation of notifyList in runtime/sema.go. Size and alignment must
// agree.
type notifyList struct {
wait uint32
notify uint32
lock uintptr // key field of the mutex
head unsafe.Pointer
tail unsafe.Pointer
}

NewCond

NewCond returns a new Cond with Locker l.

1
2
3
4
// NewCond returns a new Cond with Locker l.
func NewCond(l Locker) *Cond {
return &Cond{L: l}
}

Wait

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
// 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:
//
// c.L.Lock()
// for !condition() {
// c.Wait()
// }
// ... make use of condition ...
// c.L.Unlock()
//
func (c *Cond) Wait() {
c.checker.check() //检查有没有被copy
t := runtime_notifyListAdd(&c.notify)
c.L.Unlock()
runtime_notifyListWait(&c.notify, t)
c.L.Lock()
}

check

1
2
3
4
5
6
7
8
9
10
// copyChecker holds back pointer to itself to detect object copying.
type copyChecker uintptr

func (c *copyChecker) check() {
if uintptr(*c) != uintptr(unsafe.Pointer(c)) &&
!atomic.CompareAndSwapUintptr((*uintptr)(c), 0, uintptr(unsafe.Pointer(c))) &&
uintptr(*c) != uintptr(unsafe.Pointer(c)) {
panic("sync.Cond is copied")
}
}

Signal

1
2
3
4
5
6
7
8
// 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 (c *Cond) Signal() {
c.checker.check()
runtime_notifyListNotifyOne(&c.notify)
}

Broadcast

1
2
3
4
5
6
7
8
// Broadcast wakes all goroutines waiting on c.
//
// It is allowed but not required for the caller to hold c.L
// during the call.
func (c *Cond) Broadcast() {
c.checker.check()
runtime_notifyListNotifyAll(&c.notify)
}

基本比较简单,麻烦的是runtime系列函数,我在别的文章单独整理吧.

reference

[1]https://golang.org/pkg/sync/#Cond

----------- ending -----------