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
}()
相关推荐
爱勇宝15 分钟前
2026一人公司生存指南:用AI大模型,90天跑出你的第一条现金流
前端·后端·架构
golang学习记17 分钟前
Go 并发编程:原子操作(Atomics)完全指南
后端
哈里谢顿1 小时前
`127.0.0.1` 和 `0.0.0.0` 有何区别?通过验证 demo来展示
后端
树獭叔叔1 小时前
08-大模型后训练的指令微调SFT:LoRA让大模型微调成本降低99%
后端·aigc·openai
苏三说技术1 小时前
我终于遇到一台真正懂程序员的显示器!
后端
Re_zero2 小时前
线上日志被清空?这段仅10行的 IO 代码里竟然藏着3个毒瘤
java·后端
花落人散处2 小时前
流式输出——解决 HITL 难题 (SpringAIAlibaba)
后端
BingoGo3 小时前
OpenSwoole 26.2.0 发布:支持 PHP 8.5、io_uring 后端及协程调试改进
后端·php
JaguarJack3 小时前
OpenSwoole 26.2.0 发布:支持 PHP 8.5、io_uring 后端及协程调试改进
后端·php·服务端
Victor3563 小时前
MongoDB(18)如何向MongoDB集合中插入文档?
后端