面试题答案
一键面试sync.Cond
适用场景
- 资源竞争与协调:当多个协程需要访问共享资源,并且根据资源的状态来决定是否等待或执行时,
sync.Cond
可以发挥作用。例如,在生产者 - 消费者模型中,生产者和消费者都需要访问共享缓冲区,并且根据缓冲区的状态(满或空)来决定是否等待。 - 多协程协作:当一组协程需要在某个条件满足时被唤醒并执行特定操作时,
sync.Cond
很有用。比如,在一个任务队列中,当有新任务到达时,等待的工作协程需要被唤醒去处理任务。
生产者 - 消费者模型代码实现
package main
import (
"fmt"
"sync"
)
// 共享缓冲区
type Buffer struct {
data []int
capacity int
index int
mutex sync.Mutex
cond *sync.Cond
}
// 创建新的缓冲区
func NewBuffer(capacity int) *Buffer {
b := &Buffer{
data: make([]int, 0, capacity),
capacity: capacity,
index: 0,
}
b.cond = sync.NewCond(&b.mutex)
return b
}
// 生产者向缓冲区写入数据
func (b *Buffer) Produce(value int) {
b.mutex.Lock()
defer b.mutex.Unlock()
for len(b.data) == b.capacity {
// 缓冲区满,等待
b.cond.Wait()
}
b.data = append(b.data, value)
b.index++
fmt.Printf("Produced: %d\n", value)
// 唤醒所有等待的消费者
b.cond.Broadcast()
}
// 消费者从缓冲区读取数据
func (b *Buffer) Consume() int {
b.mutex.Lock()
defer b.mutex.Unlock()
for len(b.data) == 0 {
// 缓冲区空,等待
b.cond.Wait()
}
value := b.data[0]
b.data = b.data[1:]
fmt.Printf("Consumed: %d\n", value)
// 唤醒所有等待的生产者
b.cond.Broadcast()
return value
}
你可以使用以下方式测试:
func main() {
buffer := NewBuffer(2)
var wg sync.WaitGroup
wg.Add(2)
// 生产者
go func() {
defer wg.Done()
for i := 0; i < 3; i++ {
buffer.Produce(i)
}
}()
// 消费者
go func() {
defer wg.Done()
for i := 0; i < 3; i++ {
buffer.Consume()
}
}()
wg.Wait()
}