在并发编程中,协调多个协程之间的操作是一项常见的需求。条件变量(Condition Variable)是用于解决多个协程之间复杂协调问题的一种机制。条件变量配合互斥锁(Mutex
)使用,可以让一组协程等待某个条件成立后再继续进行,而不会一直消耗 CPU 资源进行忙等待。
本文将详细介绍 Golang 中 sync
包提供的 Cond
类型,并通过示例代码展示如何使用 Cond
进行协程同步。
Cond
是条件变量(Condition Variable)的简称,主要有以下三个方法:
Wait()
:
Wait()
会自动释放关联的互斥锁,并将当前协程置于等待状态。Wait()
会在返回前重新获得锁,以确保条件仍然满足。Signal()
:
Signal()
只是唤醒其中一个。Broadcast()
:
以下是一个使用 Cond
编写的生产者-消费者模型示例代码:
package main
import (
"fmt"
"sync"
"time"
)
type Queue struct {
items []int
cond *sync.Cond
}
func NewQueue() *Queue {
return &Queue{
items: make([]int, 0),
cond: sync.NewCond(&sync.Mutex{}),
}
}
func (q *Queue) Enqueue(item int) {
q.cond.L.Lock()
q.items = append(q.items, item)
q.cond.Signal() // 通知等待的消费者
q.cond.L.Unlock()
}
func (q *Queue) Dequeue() int {
q.cond.L.Lock()
for len(q.items) == 0 {
q.cond.Wait() // 等待 until 队列非空
}
item := q.items[0]
q.items = q.items[1:]
q.cond.L.Unlock()
return item
}
func main() {
q := NewQueue()
// 消费者
go func() {
for {
item := q.Dequeue()
fmt.Println("Consumed:", item)
}
}()
// 生产者
for i := 1; i <= 10; i++ {
fmt.Println("Producing:", i)
q.Enqueue(i)
time.Sleep(time.Second)
}
}
定义队列结构体:
type Queue struct {
items []int
cond *sync.Cond
}
func NewQueue() *Queue {
return &Queue{
items: make([]int, 0),
cond: sync.NewCond(&sync.Mutex{}),
}
}
这里定义了一个 Queue
结构体,包含一个 items
切片用于存储队列中的元素,以及一个条件变量 cond
。
入队操作:
func (q *Queue) Enqueue(item int) {
q.cond.L.Lock()
q.items = append(q.items, item)
q.cond.Signal() // 通知等待的消费者
q.cond.L.Unlock()
}
在入队操作中,先获取互斥锁,然后将元素添加到队列中,并通过 Signal()
方法通知等待的消费者。
出队操作:
func (q *Queue) Dequeue() int {
q.cond.L.Lock()
for len(q.items) == 0 {
q.cond.Wait() // 等待 until 队列非空
}
item := q.items[0]
q.items = q.items[1:]
q.cond.L.Unlock()
return item
}
在出队操作中,先获取互斥锁,然后检查队列是否为空。如果队列为空,则调用 Wait()
方法等待。队列非空时,取出队列头部的元素并返回。
生产者和消费者:
func main() {
q := NewQueue()
// 消费者
go func() {
for {
item := q.Dequeue()
fmt.Println("Consumed:", item)
}
}()
// 生产者
for i := 1; i <= 10; i++ {
fmt.Println("Producing:", i)
q.Enqueue(i)
time.Sleep(time.Second)
}
}
在 main
函数中,创建一个队列实例,启动一个消费者协程,不断从队列中取出元素并打印。主协程作为生产者,不断向队列中添加元素。
通过条件变量 Cond
配合互斥锁 Mutex
,我们可以轻松实现协程之间的同步与协调,避免忙等待,提高程序的效率和响应速度。本文通过一个简单的生产者-消费者模型示例,展示了如何在 Golang 中使用条件变量进行协程同步。希望本文能帮助你更好地理解和应用条件变量。
如果您喜欢我的文章,请点击下面按钮随意打赏,您的支持是我最大的动力。
最新评论