Golang sync.Cond 简介与用法

Cond 实现了一个条件变量,在 Locker 的基础上增加的一个消息通知的功能,保存了一个通知列表,用来唤醒一个或所有因等待条件变量而阻塞的 Go 程,以此来实现多个 Go 程间的同步。

type Cond struct {
    // L is held while observing or changing the condition
	L Locker
	// contains filtered or unexported fields
}

// 创建一个带锁的条件变量,Locker 通常是一个 *Mutex 或 *RWMutex
func NewCond(l Locker) *Cond

// 唤醒所有因等待条件变量 c 阻塞的 goroutine
func (c *Cond) Broadcast()

// 唤醒一个因等待条件变量 c 阻塞的 goroutine
func (c *Cond) Signal()

// 等待 c.L 解锁并挂起 goroutine,在稍后恢复执行后,Wait 返回前锁定 c.L,只有当被 Broadcast 和 Signal 唤醒,Wait 才能返回
func (c *Cond) Wait()

注意:在调用 Signal,Broadcast 之前,应确保目标 Go 程进入 Wait 阻塞状态。

Cond代码示例:

package main

import (
    "fmt"
    "sync"
    "time"
)

var locker = new(sync.Mutex)
var cond = sync.NewCond(locker)

func main() {
    for i := 0; i < 10; i++ {
        go func(x int) {
            cond.L.Lock()         //获取锁
            defer cond.L.Unlock() //释放锁
            cond.Wait()           //等待通知,阻塞当前goroutine
            fmt.Println(x)
        }(i)
    }   
    time.Sleep(time.Second * 1)	// 睡眠1秒,使所有goroutine进入 Wait 阻塞状态
    fmt.Println("Signal...")
    cond.Signal()               // 1秒后下发一个通知给已经获取锁的goroutine
    time.Sleep(time.Second * 1)
    fmt.Println("Signal...")
    cond.Signal()               // 1秒后下发下一个通知给已经获取锁的goroutine
    time.Sleep(time.Second * 1)
    cond.Broadcast()            // 1秒后下发广播给所有等待的goroutine
    fmt.Println("Broadcast...")
    time.Sleep(time.Second * 1)	// 睡眠1秒,等待所有goroutine执行完毕
}

多次运行结果不一致,示例输出:

Signal...
4
Signal...
0
Broadcast...
7
1
2
3
5
9
6
8

注意:条件变量和锁结合使用,在并发时如果逻辑不严谨容易发生死锁,所以尽量不要使用条件变量,推荐用 sync.WaitGroup 来实现并发时 Go 程间的同步。

参考文章

[1] Package sync.Cond
[2] Golang Cond源码分析

你可能感兴趣的:(Go)