This is a creation in Article, where the information may have evolved or changed.
The main function of cond is to acquire a lock, and the Wait () method waits for a notification to proceed with the next lock release, which controls the appropriate release of the lock, the release frequency, and the wait and notification for goroutine in the concurrency environment.
Sync for Golang 1.9. Cond, the same as the Golang 1.10. Source code location: Sync\cond.go.
Structural body
type Cond struct {noCopy noCopy // noCopy可以嵌入到结构中,在第一次使用后不可复制,使用go vet作为检测使用// 根据需求初始化不同的锁,如*Mutex 和 *RWMutexL Lockernotify notifyList // 通知列表,调用Wait()方法的goroutine会被放入list中,每次唤醒,从这里取出checker copyChecker // 复制检查,检查cond实例是否被复制}
Take a look at the wait queue notifyList
structure:
type notifyList struct {wait uint32notify uint32lock uintptrhead unsafe.Pointertail unsafe.Pointer}
Function
Newcond
Equivalent Cond
constructor that is used for initialization Cond
.
The argument is initialized for the locker instance and must be a reference or pointer when passing arguments, such as &sync. mutex{} or new (sync. Mutex), or it will report an exception: cannot use lock (type sync.Mutex) as type sync.Locker in argument to sync.NewCond
.
You can think about why it must be a pointer. Know can give me a message to answer.
func NewCond(l Locker) *Cond {return &Cond{L: l}}
Wait
Wait for auto unlock C. L and Pause execution call Goroutine. After resuming execution, wait for lock C. L before returning. Unlike other systems, the wait cannot be returned unless it is awakened by a broadcast or signal.
Because C. When waiting for the first recovery, L is not locked, and the caller usually cannot assume that the condition is correct when the wait is returned. Instead, the caller should wait in the loop:
func (c *Cond) Wait() { // 检查c是否是被复制的,如果是就panicc.checker.check()// 将当前goroutine加入等待队列t := runtime_notifyListAdd(&c.notify)// 解锁c.L.Unlock()// 等待队列中的所有的goroutine执行等待唤醒操作runtime_notifyListWait(&c.notify, t)c.L.Lock()}
Determines whether the cond is copied.
type copyChecker uintptrfunc (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
A goroutine in the wake-up waiting queue, which is generally a goroutine in any wake queue, why is there no FIFO mode selected? This is because FIFO mode is inefficient, although supported, but rarely used.
func (c *Cond) Signal() { // 检查c是否是被复制的,如果是就panicc.checker.check()// 通知等待列表中的一个 runtime_notifyListNotifyOne(&c.notify)}
Broadcast
Wakes all goroutine in the wait queue.
func (c *Cond) Broadcast() { // 检查c是否是被复制的,如果是就panicc.checker.check()// 唤醒等待队列中所有的goroutineruntime_notifyListNotifyAll(&c.notify)}
Instance
package mainimport ("FMT" "Sync" "Time") var locker = new (sync. Mutex) var cond = sync. Newcond (Locker) func main () {for i: = 0; i <; i++ {go func (x int) {cond. L.lock ()//Get lock defer cond. L.unlock ()//release lock cond. Wait ()//waits for notification to block the current GOROUTINEFMT. PRINTLN (x) time. Sleep (time. Second * 1)} (i)}time. Sleep (time. Second * 1) fmt. Println ("Signal ...") cond. Signal ()//Send a notification to the goroutinetime that has acquired the lock. Sleep (time. Second * 1) cond. Signal ()///3 seconds after sending a notification to the goroutinetime that has acquired the lock. Sleep (time. Second * 3) cond. Broadcast ()///3 seconds after the broadcast to all the waiting goroutinefmt. PRINTLN ("Broadcast ...") time. Sleep (time. Second *)}