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
}()
相关推荐
BIGSHU09232 分钟前
java多线程场景3-并发处理和异步请求
java·开发语言·python
Java水解7 分钟前
深入浅出:在 Koa 中实现优雅的中间件依赖注入
后端·koa
_OP_CHEN11 分钟前
数据结构(C语言篇):(十一)二叉树概念介绍
c语言·开发语言·数据结构·二叉树·学习笔记··
lssjzmn18 分钟前
构建实时消息应用:Spring Boot + Vue 与 WebSocket 的有机融合
java·后端·架构
金銀銅鐵21 分钟前
[Java] 浅析可重复注解(Repeatable Annotation) 是如何实现的
java·后端
柯南二号21 分钟前
【设计模式】【观察者模式】实例
java·开发语言·servlet
用户81744134274821 分钟前
Kubernetes集群核心概念 Service
后端
掘金一周24 分钟前
凌晨零点,一个TODO,差点把我们整个部门抬走 | 掘金一周 9.11
前端·人工智能·后端
yeyong24 分钟前
日志告警探讨,我问deepseek答,关于elastalert
后端
Cyan_RA929 分钟前
SpringMVC 执行流程分析 详解(图解SpringMVC执行流程)
java·人工智能·后端·spring·mvc·ssm·springmvc