面试题答案
一键面试sync.Cond
原理
sync.Cond
基于一个底层锁(sync.Mutex
或sync.RWMutex
)来实现条件变量。它的主要作用是让一组goroutine在满足特定条件时被唤醒。
Wait
方法
Wait
方法会释放与之关联的锁,并阻塞当前goroutine,将其放入等待队列。- 当
Wait
被唤醒时(通过Signal
或Broadcast
),它会重新获取锁并继续执行。
Signal
方法
Signal
方法唤醒等待队列中的一个随机的goroutine。- 如果没有等待的goroutine,
Signal
不做任何操作。
Broadcast
方法
Broadcast
方法唤醒等待队列中的所有goroutine。- 如果没有等待的goroutine,
Broadcast
不做任何操作。
生产者 - 消费者问题代码实现
package main
import (
"fmt"
"sync"
)
type Queue struct {
items []int
max int
mu sync.Mutex
cond *sync.Cond
}
func NewQueue(max int) *Queue {
q := &Queue{
max: max,
}
q.cond = sync.NewCond(&q.mu)
return q
}
func (q *Queue) Enqueue(item int) {
q.mu.Lock()
for len(q.items) == q.max {
q.cond.Wait()
}
q.items = append(q.items, item)
fmt.Printf("Produced: %d\n", item)
q.cond.Signal()
q.mu.Unlock()
}
func (q *Queue) Dequeue() int {
q.mu.Lock()
for len(q.items) == 0 {
q.cond.Wait()
}
item := q.items[0]
q.items = q.items[1:]
fmt.Printf("Consumed: %d\n", item)
q.cond.Signal()
q.mu.Unlock()
return item
}
func main() {
queue := NewQueue(2)
var wg sync.WaitGroup
wg.Add(2)
go func() {
defer wg.Done()
for i := 1; i <= 3; i++ {
queue.Enqueue(i)
}
}()
go func() {
defer wg.Done()
for i := 1; i <= 3; i++ {
queue.Dequeue()
}
}()
wg.Wait()
}
在上述代码中:
Queue
结构体包含一个items
切片用于存储数据,max
表示队列的最大容量,mu
是一个互斥锁,cond
是条件变量。NewQueue
函数初始化Queue
并创建条件变量。Enqueue
方法在队列满时调用Wait
阻塞,直到有空间;添加元素后调用Signal
唤醒等待的消费者。Dequeue
方法在队列为空时调用Wait
阻塞,直到有数据;取出元素后调用Signal
唤醒等待的生产者。main
函数启动一个生产者和一个消费者,并等待它们完成。