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
}()
相关推荐
期待のcode7 分钟前
原子操作类LongAdder
java·开发语言
lly2024061 小时前
C 语言中的结构体
开发语言
JAVA+C语言1 小时前
如何优化 Java 多主机通信的性能?
java·开发语言·php
青岑CTF3 小时前
攻防世界-Ics-05-胎教版wp
开发语言·安全·web安全·网络安全·php
Li emily3 小时前
如何通过外汇API平台快速实现实时数据接入?
开发语言·python·api·fastapi·美股
APIshop3 小时前
Java 实战:调用 item_search_tmall 按关键词搜索天猫商品
java·开发语言·数据库
血小板要健康3 小时前
Java基础常见面试题复习合集1
java·开发语言·经验分享·笔记·面试·学习方法
淼淼7634 小时前
安装jdk1.8
java·开发语言
PfCoder4 小时前
WinForm真入门(23)---PictureBox 控件详细用法
开发语言·windows·c#·winform
Legendary_0084 小时前
Type-C 一拖二快充线:突破单口限制的技术逻辑
c语言·开发语言