面试题答案
一键面试基本原理
sync.Mutex
:它是Go语言标准库提供的互斥锁,用于保护共享资源,确保同一时间只有一个goroutine能够访问共享资源,防止数据竞争。sync.Cond
:条件变量,它需要与一个互斥锁sync.Mutex
配合使用。sync.Cond
可以让一个或多个goroutine在满足特定条件时被唤醒。当条件不满足时,goroutine可以通过Cond.Wait
方法释放持有的互斥锁并进入等待状态,当条件满足时,其他goroutine可以通过Cond.Signal
或Cond.Broadcast
方法唤醒等待的goroutine。Cond.Wait
方法在进入等待状态前会自动释放它持有的互斥锁,当被唤醒时会重新获取互斥锁。
代码示例
package main
import (
"fmt"
"sync"
)
type Queue struct {
data []int
cond *sync.Cond
mutex sync.Mutex
}
func (q *Queue) Enqueue(item int) {
q.mutex.Lock()
defer q.mutex.Unlock()
q.data = append(q.data, item)
fmt.Printf("Produced: %d\n", item)
q.cond.Broadcast()
}
func (q *Queue) Dequeue() int {
q.mutex.Lock()
defer q.mutex.Unlock()
for len(q.data) == 0 {
q.cond.Wait()
}
item := q.data[0]
q.data = q.data[1:]
fmt.Printf("Consumed: %d\n", item)
return item
}
func main() {
queue := &Queue{
cond: sync.NewCond(&queue.mutex),
}
var wg sync.WaitGroup
wg.Add(2)
// 生产者
go func() {
defer wg.Done()
for i := 0; i < 5; i++ {
queue.Enqueue(i)
}
}()
// 消费者
go func() {
defer wg.Done()
for i := 0; i < 5; i++ {
queue.Dequeue()
}
}()
wg.Wait()
}
在这段代码中:
Queue
结构体包含一个整数数组data
作为共享队列,一个sync.Cond
类型的条件变量cond
和一个sync.Mutex
类型的互斥锁mutex
。Enqueue
方法用于向队列中添加数据,它首先获取互斥锁,添加数据后通过cond.Broadcast
唤醒所有等待的goroutine。Dequeue
方法用于从队列中取出数据,它先获取互斥锁,当队列为空时通过cond.Wait
等待,直到被唤醒且队列中有数据时取出数据。- 在
main
函数中启动了一个生产者goroutine和一个消费者goroutine,分别向队列中添加和取出数据。