如何在Golang中实现条件变量同步

条件变量是go中协调goroutine的同步机制,需与互斥锁配合使用。sync.Cond提供Wait、signal、Broadcast方法,用于等待条件满足后唤醒goroutine。消费者用for循环加Wait等待,生产者修改状态后调用Signal或Broadcast通知,确保安全访问共享数据,避免竞态条件和虚假唤醒。

如何在Golang中实现条件变量同步

golang中,条件变量用于协调多个goroutine之间的执行顺序,尤其适用于等待某个条件成立后再继续执行的场景。Go语言通过 sync.Cond 类型提供了对条件变量的支持,它通常与互斥锁(sync.Mutex 或 sync.RWMutex)配合使用,确保共享数据的安全访问。

什么是条件变量

条件变量是一种同步机制,允许goroutine在某个条件不满足时挂起等待,并在其他goroutine改变状态后被唤醒。它不是用来保护临界区的,而是用来“等待-通知”协作。

sync.Cond 包含三个核心方法:

  • Wait():释放锁并阻塞当前goroutine,直到被 Signal 或 Broadcast 唤醒。
  • Signal():唤醒一个正在等待的goroutine。
  • Broadcast():唤醒所有等待的goroutine。

如何正确使用 sync.Cond

使用条件变量的关键是结合互斥锁和循环检查条件,避免虚假唤醒或竞态条件。

立即学习go语言免费学习笔记(深入)”;

示例:生产者-消费者模型

假设有一个共享缓冲区,生产者向其中添加数据,消费者等待数据可用后再读取。

 package main <p>import ( "fmt" "sync" "time" )</p><p>func main() { var mu sync.Mutex cond := sync.NewCond(&mu) items := make([]int, 0, 10)</p><pre class='brush:php;toolbar:false;'>// 消费者 goroutine go func() {     mu.Lock()     for len(items) == 0 {         cond.Wait() // 等待有数据     }     // 取出数据(实际项目中可能需要更复杂的逻辑)     item := items[0]     items = items[1:]     fmt.Printf("消费了: %dn", item)     mu.Unlock() }()  // 生产者 goroutine go func() {     mu.Lock()     items = append(items, 42)     fmt.Println("生产了数据")     cond.Signal() // 通知等待的消费者     mu.Unlock() }()  // 主线程等待一段时间让goroutine完成 time.Sleep(1 * time.Second)

}

如何在Golang中实现条件变量同步

如知AI笔记

如知笔记——支持markdown的在线笔记,支持ai智能写作、AI搜索,支持DeepseekR1满血大模型

如何在Golang中实现条件变量同步27

查看详情 如何在Golang中实现条件变量同步

说明:

  • 消费者在进入 Wait 前必须持有锁,并用 for 循环检查条件,防止虚假唤醒。
  • Wait 方法会自动释放锁,当被唤醒后重新获取锁再返回。
  • 生产者修改数据后调用 Signal 通知至少一个等待者。

广播通知 Broadcast 的使用场景

当你有多个等待者,并且一次状态变化影响所有等待者时,应使用 Broadcast。

例如,关闭服务、清空队列等全局操作。

 // 唤醒所有等待的goroutine cond.Broadcast() 

比如多个消费者等待同一个队列,生产者一次性放入多个元素,可以用 Broadcast 让所有消费者尝试获取任务。

注意事项与最佳实践

  • 总是使用 for 循环检查条件,而不是 if,以应对虚假唤醒。
  • 每次调用 Wait 前必须持有锁
  • Signal 和 Broadcast 应在改变条件状态后调用。
  • 即使没有goroutine在等待,调用 Signal 或 Broadcast 也不会出错。
  • 注意死锁风险:不要在未解锁的情况下长时间运行或再次等待。

基本上就这些。sync.Cond 虽不如 channel 常见,但在某些需要精确控制唤醒行为的场景下非常有用。

上一篇
下一篇
text=ZqhQzanResources