在并发编程中,我们经常需要协调多个 Goroutine 的执行顺序。例如:当某个共享资源尚未就绪时,其他 Goroutine 应该等待;一旦资源准备好了,就需要通知(唤醒)等待中的 Goroutine。在 Go语言 中,sync.Cond 提供了一种高效的方式来实现这种“等待-通知”机制。
本文将带你从零开始,深入理解 sync.Cond 条件变量 的工作原理,特别是其唤醒机制,并通过一个完整的示例帮助你掌握实际用法。
sync.Cond 是 Go 标准库 sync 包提供的一个条件变量类型。它允许一组 Goroutine 在某个条件不满足时挂起(等待),并在条件满足时被唤醒。
与互斥锁(sync.Mutex)不同,sync.Cond 本身不提供互斥保护,但它必须与一个锁(通常是 *sync.Mutex 或 *sync.RWMutex)配合使用。

Wait():挂起当前 Goroutine,直到被唤醒。调用前必须持有关联的锁,调用后会自动释放锁,并在被唤醒后重新获取锁。Signal():唤醒一个正在等待的 Goroutine(如果有)。Broadcast():唤醒所有正在等待的 Goroutine。使用 sync.NewCond(l Locker) 创建一个 *sync.Cond 实例,其中 l 必须是一个实现了 Locker 接口的锁(如 *sync.Mutex)。
var mu sync.Mutexcond := sync.NewCond(&mu)假设我们有一个任务队列,消费者 Goroutine 需要等待任务就绪后再处理。我们可以使用 sync.Cond 来实现这一逻辑。
package mainimport ( "fmt" "sync" "time")func main() { var mu sync.Mutex cond := sync.NewCond(&mu) taskReady := false // 消费者 Goroutine go func() { mu.Lock() for !taskReady { fmt.Println("等待任务就绪...") cond.Wait() // 释放锁并等待,被唤醒后重新获取锁 } fmt.Println("任务已就绪,开始处理!") mu.Unlock() }() // 主 Goroutine 模拟任务准备 time.Sleep(2 * time.Second) mu.Lock() taskReady = true fmt.Println("任务已准备好,通知消费者...") cond.Signal() // 唤醒一个等待的 Goroutine mu.Unlock() time.Sleep(1 * time.Second) // 等待消费者完成}运行结果可能如下:
等待任务就绪...任务已准备好,通知消费者...任务已就绪,开始处理!
1. 必须在持有锁的情况下调用 Signal() 或 Broadcast()。这是为了确保状态变更和通知操作的原子性。
2. Wait() 会在内部自动释放锁,并在被唤醒后重新获取锁。因此,在 Wait() 返回后,你可以安全地读取共享状态。
3. 使用 for 循环检查条件(而不是 if),是为了防止“虚假唤醒”(spurious wakeup)——即 Goroutine 被唤醒但条件仍未满足。
Signal():只唤醒一个等待的 Goroutine。适用于“单消费者”或“任务只需处理一次”的场景。Broadcast():唤醒所有等待的 Goroutine。适用于“多消费者”或“所有等待者都需要响应状态变化”的场景。通过本文,你应该已经掌握了 Go语言 中 sync.Cond 条件变量的基本用法及其唤醒机制。记住:sync.Cond 不是万能的,在大多数简单场景下,使用 channel 可能更简洁、更符合 Go 的并发哲学。但在需要精细控制多个 Goroutine 的等待/唤醒行为时,sync.Cond 是一个强大而高效的工具。
希望这篇教程能帮助你深入理解 sync.Cond 条件变量,并在实际项目中合理运用其唤醒机制来构建高性能的并发程序。
本文由主机测评网于2025-12-04发表在主机测评网_免费VPS_免费云服务器_免费独立服务器,如有疑问,请联系我们。
本文链接:https://www.vpshk.cn/2025122842.html