Golang基础知识—cond

cond 通常指 sync.Cond,它是标准库 sync 包中用于实现 条件变量 的同步原语。条件变量在多 goroutine 协作场景中非常有用,尤其在需要根据特定条件协调多个 goroutine 的执行顺序时。


sync.Cond 的核心作用

条件变量用于 等待某个条件满足通知其他等待者条件已满足。常用于以下场景:

  • 一个或多个 goroutine 需要等待某个条件成立才能继续执行。

  • 某个 goroutine 负责修改条件,并通知其他等待的 goroutine。


sync.Cond 的组成

复制代码
type Cond struct {
    L Locker // 关联的锁(通常是 sync.Mutex 或 sync.RWMutex)
}

主要方法:

  1. Wait()

    • 调用前必须持有锁(c.L.Lock())。

    • 释放锁并挂起当前 goroutine,等待被唤醒。

    • 被唤醒后重新获取锁,继续执行。

  2. Signal()

    • 唤醒一个等待的 goroutine(随机选择一个)。
  3. Broadcast()

    • 唤醒所有等待的 goroutine。

基本使用模式

复制代码
var (
    mu    sync.Mutex
    cond  = sync.NewCond(&mu)
    ready bool
)

// 等待条件满足的 goroutine
func waiter() {
    mu.Lock()
    defer mu.Unlock()
    for !ready { // 必须用循环检查条件(防止虚假唤醒)
        cond.Wait()
    }
    // 执行条件满足后的操作
}

// 修改条件并通知的 goroutine
func setter() {
    mu.Lock()
    ready = true
    mu.Unlock()
    cond.Signal() // 或 cond.Broadcast()
}
复制代码

经典示例:生产者-消费者

复制代码
package main

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

func main() {
    var mu sync.Mutex
    cond := sync.NewCond(&mu)
    queue := make([]int, 0)

    // 消费者
    go func() {
        for {
            mu.Lock()
            for len(queue) == 0 {
                cond.Wait() // 等待队列非空
            }
            item := queue[0]
            queue = queue[1:]
            fmt.Println("Consumed:", item)
            mu.Unlock()
        }
    }()

    // 生产者
    for i := 1; i <= 5; i++ {
        time.Sleep(1 * time.Second)
        mu.Lock()
        queue = append(queue, i)
        fmt.Println("Produced:", i)
        cond.Signal() // 通知消费者
        mu.Unlock()
    }
}

关键注意事项

  1. 必须用循环检查条件
    Wait() 返回后条件可能仍未满足(如虚假唤醒),需循环检查:

    复制代码
    for conditionNotMet {
        cond.Wait()
    }
  2. 调用 Wait() 前必须持有锁

    否则会导致竞态条件。

  3. Signal vs Broadcast

    • Signal:唤醒一个等待者(适用于单消费者)。

    • Broadcast:唤醒所有等待者(适用于多消费者或条件变化影响所有等待者)。


何时使用 sync.Cond

  • 需要 基于复杂条件协调多个 goroutine

  • 需要 同时唤醒多个等待者(如资源释放时唤醒所有等待的 goroutine)。

对于简单场景,优先考虑使用 channel(Go 的推荐并发模式):

复制代码
// 用 channel 实现类似功能
ch := make(chan int)

// 生产者
go func() {
    ch <- 1
}()

// 消费者
go func() {
    item := <-ch
}()
相关推荐
海绵宝宝贾克斯儿1 小时前
C++中如何实现一个单例模式?
开发语言·c++·单例模式
史迪仔01121 小时前
[python] Python单例模式:__new__与线程安全解析
开发语言·python·单例模式
冼紫菜1 小时前
[特殊字符]CentOS 7.6 安装 JDK 11(适配国内服务器环境)
java·linux·服务器·后端·centos
isyangli_blog1 小时前
(1-4)Java Object类、Final、注解、设计模式、抽象类、接口、内部类
java·开发语言
三块钱07941 小时前
【原创】基于视觉大模型gemma-3-4b实现短视频自动识别内容并生成解说文案
开发语言·python·音视频
易只轻松熊1 小时前
C++(20): 文件输入输出库 —— <fstream>
开发语言·c++·算法
芯眼1 小时前
ALIENTEK精英STM32F103开发板 实验0测试程序详解
开发语言·c++·stm32·单片机·嵌入式硬件·社交电子
青出于兰2 小时前
C语言| 指针变量的定义
c语言·开发语言
玉笥寻珍2 小时前
筑牢信息安全防线:涉密计算机与互联网隔离的理论实践与风险防控
开发语言·计算机网络·安全·计算机外设·php·安全架构·安全性测试
蓝莓味柯基2 小时前
Lodash isEqual 方法源码实现分析
开发语言