• Go语言中的条件变量


    Go语言sync package提供了条件变量(condition variable)类型:

    type Cond struct {
            // L is held while observing or changing the condition
            L Locker
            // contains filtered or unexported fields
    }
    type Cond
        func NewCond(l Locker) *Cond
        func (c *Cond) Broadcast()
        func (c *Cond) Signal()
        func (c *Cond) Wait()
    type Locker
    
    type Locker interface {
            Lock()
            Unlock()
    }
    A Locker represents an object that can be locked and unlocked.
    

    NewCond()函数输入参数是一个Locker接口类型,即实现了锁功能的变量。Broadcast()函数通知所有等待在condition variablegoroutine,而Signal()函数只会通知其中的一个goroutineWait()会让goroutine阻塞在condition variable,等待条件成立。通常的做法是:

    c.L.Lock()
    for !condition() {
        c.Wait()
    }
    ... make use of condition ...
    c.L.Unlock()
    

    进入Wait()函数会解锁,离开Wait()函数会重新加锁。由于在“解锁->收到通知->重新加锁”这段逻辑中间有可能另一个同样wait()goroutine抢先一步改变了条件,导致当前goroutine的条件不再成立,所以这块要使用循环检测。参考下例:

    package main
    
    import (
        "sync"
        "time"
        "fmt"
    )
    
    func main() {
        c := sync.NewCond(&sync.Mutex{})
        var num int
    
        for i := 1; i <= 2; i++ {
            go func(id int) {
                fmt.Println("Enter Thread ID:", id)
                c.L.Lock()
                for num != 1 {
                    fmt.Println("Enter loop: Thread ID:", id)
                    c.Wait()
                    fmt.Println("Exit loop: Thread ID:", id)
                }
                num++
                c.L.Unlock()
                fmt.Println("Exit Thread ID:", id)
            }(i)
        }
    
        time.Sleep(time.Second)
        fmt.Println("Sleep 1 second")
    
        num++
        c.Broadcast()
        time.Sleep(time.Second)
        fmt.Println("Program exit")
    }
    

    一次执行结果如下:

    Enter Thread ID: 2
    Enter loop: Thread ID: 2
    Enter Thread ID: 1
    Enter loop: Thread ID: 1
    Sleep 1 second
    Exit loop: Thread ID: 2
    Exit Thread ID: 2
    Exit loop: Thread ID: 1
    Enter loop: Thread ID: 1
    Program exit
    

    从上面例子可以看出由于goroutine 2改变了条件,导致goroutine 1重新进入循环,即多个goroutine阻塞在一个condition variable上存在着竞争的关系。

    参考资料:
    Package sync
    Condition Variables

  • 相关阅读:
    CDZSC_2015寒假新人(4)——搜索 A
    第一次组队赛---2010年全国大学生程序设计邀请赛(福州)L
    ZSC新生赛 沼跃鱼早已看穿了一切
    ZSC新生赛 聪明的员工
    CDZSC_2015寒假新人(1)——基础 I
    Linux 系统时间和硬件时间
    Python 深浅复制
    Python 函数内省
    Python 函数参数
    Python 可调用对象
  • 原文地址:https://www.cnblogs.com/ExMan/p/12622074.html
Copyright © 2020-2023  润新知