MST

星途 面试题库

面试题:Go中条件变量如何在多线程同步场景下解决生产者 - 消费者问题

在Go语言中,假设有一个生产者 - 消费者模型,生产者不断生成数据放入缓冲区,消费者从缓冲区取出数据进行处理。请使用条件变量(`sync.Cond`)实现这个模型,描述实现思路并给出关键代码片段。
42.3万 热度难度
编程语言Go

知识考点

AI 面试

面试题答案

一键面试

实现思路

  1. 定义缓冲区:使用切片或通道来作为数据的暂存区。
  2. 生产者逻辑:生成数据并将其放入缓冲区。如果缓冲区已满,生产者需要等待,直到缓冲区有空间。
  3. 消费者逻辑:从缓冲区取出数据并处理。如果缓冲区为空,消费者需要等待,直到缓冲区有数据。
  4. 使用sync.Cond:用于协调生产者和消费者的等待和唤醒操作。sync.Cond 依赖于一个 sync.Mutex 来保护共享资源(即缓冲区)。

关键代码片段

package main

import (
    "fmt"
    "sync"
    "time"
)

type Buffer struct {
    data []int
    capacity int
    mutex sync.Mutex
    cond  *sync.Cond
}

func NewBuffer(capacity int) *Buffer {
    b := &Buffer{
        data: make([]int, 0, capacity),
        capacity: capacity,
    }
    b.cond = sync.NewCond(&b.mutex)
    return b
}

// 生产者
func Producer(buffer *Buffer, id int) {
    for {
        buffer.mutex.Lock()
        for len(buffer.data) == buffer.capacity {
            buffer.cond.Wait()
        }
        num := id * 10 + len(buffer.data)
        buffer.data = append(buffer.data, num)
        fmt.Printf("Producer %d produced %d\n", id, num)
        buffer.cond.Broadcast()
        buffer.mutex.Unlock()
        time.Sleep(time.Millisecond * 500)
    }
}

// 消费者
func Consumer(buffer *Buffer, id int) {
    for {
        buffer.mutex.Lock()
        for len(buffer.data) == 0 {
            buffer.cond.Wait()
        }
        num := buffer.data[0]
        buffer.data = buffer.data[1:]
        fmt.Printf("Consumer %d consumed %d\n", id, num)
        buffer.cond.Broadcast()
        buffer.mutex.Unlock()
        time.Sleep(time.Millisecond * 1000)
    }
}

main 函数中可以这样使用:

func main() {
    buffer := NewBuffer(5)
    go Producer(buffer, 1)
    go Producer(buffer, 2)
    go Consumer(buffer, 1)
    go Consumer(buffer, 2)

    select {}
}