面试题答案
一键面试避免写饥饿的方法
- 写优先策略:在进行读操作前,先检查是否有写操作在等待。如果有写操作等待,那么读操作应该等待写操作完成后再执行。这样可以保证写操作不会因为读操作不断进行而一直得不到执行。
- 公平调度:使用一个计数器记录写操作等待的次数或者时间,当达到一定阈值时,优先处理写操作。
示例代码
package main
import (
"fmt"
"sync"
"time"
)
var (
data int
mu sync.RWMutex
writeCh = make(chan struct{})
)
func writer(id int, wg *sync.WaitGroup) {
defer wg.Done()
for i := 0; i < 5; i++ {
writeCh <- struct{}{} // 发出写请求信号
mu.Lock()
data = id * 10 + i
fmt.Printf("Writer %d writing: %d\n", id, data)
mu.Unlock()
<-writeCh // 完成写操作,释放信号
time.Sleep(100 * time.Millisecond)
}
}
func reader(id int, wg *sync.WaitGroup) {
defer wg.Done()
for i := 0; i < 10; i++ {
select {
case <-writeCh:
// 如果有写操作在等待,先让出资源
<-writeCh
default:
}
mu.RLock()
fmt.Printf("Reader %d reading: %d\n", id, data)
mu.RUnlock()
time.Sleep(50 * time.Millisecond)
}
}
func main() {
var wg sync.WaitGroup
for i := 0; i < 2; i++ {
wg.Add(1)
go writer(i, &wg)
}
for i := 0; i < 5; i++ {
wg.Add(1)
go reader(i, &wg)
}
wg.Wait()
}
在上述代码中:
writeCh
用于标识是否有写操作在等待。- 读操作在加读锁前,通过
select
语句检查是否有写操作在等待,如果有则先让出资源,等待写操作完成。 - 写操作通过
writeCh
来控制,确保每次只有一个写操作在进行,并且在读操作发现有写操作等待时,读操作会等待写操作完成。这样可以有效避免写饥饿现象。