条件变量(Cond)是Go语言提供的一种同步原语,它用于等待或通知某些事件的发生。当某个事件尚未发生时,一个或多个goroutine可以通过条件变量等待该事件的发生;当事件发生时,某个goroutine可以通过条件变量通知其他等待该事件发生的goroutine。
在Go语言中,条件变量由sync包提供,其类型为sync.Cond,它包含以下几个方法:
func (c *Cond) Broadcast(): 唤醒所有等待该条件变量的goroutine。
func (c *Cond) Signal(): 唤醒等待该条件变量的某一个goroutine。
func (c *Cond) Wait(): 等待该条件变量的通知,并解锁当前的互斥锁,直到被唤醒后重新加锁。
下面是一个使用条件变量实现生产者-消费者模型的示例代码:
package main
import (
"fmt"
"sync"
"time"
)
type Queue struct {
mu sync.Mutex
cond *sync.Cond
content []int
}
func NewQueue() *Queue {
q := &Queue{content: make([]int, 0)}
q.cond = sync.NewCond(&q.mu)
return q
}
func (q *Queue) Push(val int) {
q.mu.Lock()
defer q.mu.Unlock()
q.content = append(q.content, val)
q.cond.Signal() // 通知等待该条件变量的一个goroutine
}
func (q *Queue) Pop() int {
q.mu.Lock()
defer q.mu.Unlock()
for len(q.content) == 0 {
q.cond.Wait() // 等待该条件变量的通知,并解锁当前的互斥锁
}
val := q.content[0]
q.content = q.content[1:]
return val
}
func main() {
queue := NewQueue()
var wg sync.WaitGroup
wg.Add(2)
go func() { // 生产者
for i := 0; i < 10; i++ {
queue.Push(i)
time.Sleep(time.Millisecond * 500)
}
wg.Done()
}()
go func() { // 消费者
for i := 0; i < 10; i++ {
val := queue.Pop()
fmt.Println(val)
time.Sleep(time.Millisecond * 1000)
}
wg.Done()
}()
wg.Wait()
}
在上面的示例代码中,Queue是一个线程安全的队列类型,它包含一个互斥锁和一个条件变量cond。Push方法用于往队列中添加元素,Pop方法用于从队列中取出元素。在Pop方法中,如果队列为空,则调用cond.Wait()方法等待通知,并解锁当前的互斥锁,直到被Push方法唤醒后重新加锁。在Push方法中,每次往队列中添加元素后,调用cond.Signal()方法唤醒等待该条件变量的一个goroutine。
在main函数中,启动两个goroutine,一个用于生产元素,一个用于消费元素。