MST

星途 面试题库

面试题:Go中条件变量(sync.Cond)在并发同步中的应用场景及实现

请描述在Go语言中条件变量(`sync.Cond`)适用于哪些并发同步场景。并以生产者 - 消费者模型为例,使用`sync.Cond`和`sync.Mutex`编写代码实现一个简单的生产者 - 消费者模式,其中生产者向共享缓冲区写入数据,消费者从共享缓冲区读取数据,当缓冲区满时生产者等待,当缓冲区空时消费者等待。
22.5万 热度难度
编程语言Go

知识考点

AI 面试

面试题答案

一键面试

sync.Cond适用场景

  1. 资源竞争与协调:当多个协程需要访问共享资源,并且根据资源的状态来决定是否等待或执行时,sync.Cond可以发挥作用。例如,在生产者 - 消费者模型中,生产者和消费者都需要访问共享缓冲区,并且根据缓冲区的状态(满或空)来决定是否等待。
  2. 多协程协作:当一组协程需要在某个条件满足时被唤醒并执行特定操作时,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()
}