zoukankan      html  css  js  c++  java
  • 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

  • 相关阅读:
    1.2.2 标准命令概述
    1.3 第一个Go程序
    2. 基础类型
    转载:Pixhawk源码笔记一:APM代码基本结构
    IIS6的工作进程回收
    在电脑前独坐,又已经凌晨3点了
    IT人:为什么快乐不起来
    平淡的一天,平淡的心情
    发现一个很好玩的东西
    Jmeter脚本增强检查点
  • 原文地址:https://www.cnblogs.com/ExMan/p/12622074.html
Copyright © 2011-2022 走看看