MST

星途 面试题库

面试题:Go 中 sync.Cond 的原理及应用

请详细说明 Go 语言中 sync.Cond 的原理,包括它与互斥锁(Mutex)的关系。并且结合一个实际的并发场景,例如生产者 - 消费者模型,展示如何使用 sync.Cond 来实现高效的同步与通信。
18.5万 热度难度
编程语言Go

知识考点

AI 面试

面试题答案

一键面试

Go 语言中 sync.Cond 的原理

  1. 基本概念sync.Cond 是 Go 语言标准库中用于条件变量的结构体。它允许一个或多个 goroutine 等待特定条件满足,然后再继续执行。条件变量通常与一个互斥锁配合使用,用于在共享资源的状态发生变化时通知等待的 goroutine。
  2. 原理细节
    • 等待机制:当一个 goroutine 调用 Cond.Wait() 时,它会自动释放与之关联的互斥锁(这是必须在持有互斥锁的情况下调用 Wait 的原因),然后该 goroutine 被阻塞,进入等待队列。当 Cond.Signal()Cond.Broadcast() 被调用时,等待队列中的一个或多个 goroutine 会被唤醒。唤醒后,该 goroutine 会重新获取互斥锁,然后从 Wait() 调用处继续执行。
    • 通知机制Cond.Signal() 会唤醒等待队列中的一个 goroutine,而 Cond.Broadcast() 会唤醒等待队列中的所有 goroutine。

与互斥锁(Mutex)的关系

  1. 紧密协作sync.Cond 依赖于互斥锁来保护共享资源。在调用 Cond.Wait()Cond.Signal()Cond.Broadcast() 之前,必须先获取互斥锁。这是因为共享资源的状态检查和修改需要在临界区内进行,以避免竞态条件。
  2. 互斥锁作用:互斥锁用于保证在同一时间只有一个 goroutine 能够访问共享资源,而 sync.Cond 则用于在共享资源状态发生变化时通知等待的 goroutine。

生产者 - 消费者模型示例

package main

import (
    "fmt"
    "sync"
)

type Queue struct {
    items []int
    cond  *sync.Cond
    mutex sync.Mutex
    capacity int
}

func NewQueue(capacity int) *Queue {
    q := &Queue{
        items:    make([]int, 0, capacity),
        capacity: capacity,
    }
    q.cond = sync.NewCond(&q.mutex)
    return q
}

// 生产者
func (q *Queue) Produce(item int) {
    q.mutex.Lock()
    defer q.mutex.Unlock()
    for len(q.items) == q.capacity {
        q.cond.Wait()
    }
    q.items = append(q.items, item)
    fmt.Printf("Produced: %d\n", item)
    q.cond.Signal()
}

// 消费者
func (q *Queue) Consume() int {
    q.mutex.Lock()
    defer q.mutex.Unlock()
    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()
    return item
}

你可以这样使用上述代码:

func main() {
    queue := NewQueue(2)
    var wg sync.WaitGroup
    wg.Add(2)

    go func() {
        defer wg.Done()
        for i := 0; i < 3; i++ {
            queue.Produce(i)
        }
    }()

    go func() {
        defer wg.Done()
        for i := 0; i < 3; i++ {
            queue.Consume()
        }
    }()

    wg.Wait()
}

在这个生产者 - 消费者模型中,Queue 结构体包含一个 sync.Cond 和一个 sync.Mutex。生产者在队列满时调用 cond.Wait() 等待,消费者在队列空时调用 cond.Wait() 等待。当生产者生产了新的元素或消费者消费了元素后,通过 cond.Signal() 通知等待的 goroutine。这样就实现了高效的同步与通信。