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
}()
相关推荐
菥菥爱嘻嘻4 分钟前
JS手写代码篇---手写ajax
开发语言·javascript·ajax
江梦寻10 分钟前
MacOS下Homebrew国内镜像加速指南(2025最新国内镜像加速)
开发语言·后端·python·macos·架构·策略模式
霖檬ing13 分钟前
Python——MySQL远程控制
开发语言·python·mysql
风象南17 分钟前
SpringBoot的4种死信队列处理方式
java·spring boot·后端
互联网全栈架构1 小时前
遨游Spring AI:第一盘菜Hello World
java·人工智能·后端·spring
qq_429879671 小时前
省略号和可变参数模板
开发语言·c++·算法
优秀的颜2 小时前
计算机基础知识(第五篇)
java·开发语言·分布式
CodeWithMe2 小时前
【C/C++】std::vector成员函数清单
开发语言·c++
uyeonashi2 小时前
【QT控件】输入类控件详解
开发语言·c++·qt
飞川撸码2 小时前
【LeetCode 热题100】网格路径类 DP 系列题:不同路径 & 最小路径和(力扣62 / 64 )(Go语言版)
算法·leetcode·golang·动态规划