MST

星途 面试题库

面试题:Go语言中如何通过优化读写操作顺序来避免RWMutex写饥饿

假设你有一个场景,频繁地进行读写操作,使用RWMutex来控制访问。请详细说明如何通过优化读写操作的顺序,尽可能避免写饥饿现象,并给出示例代码。
21.9万 热度难度
编程语言Go

知识考点

AI 面试

面试题答案

一键面试

避免写饥饿的方法

  1. 写优先策略:在进行读操作前,先检查是否有写操作在等待。如果有写操作等待,那么读操作应该等待写操作完成后再执行。这样可以保证写操作不会因为读操作不断进行而一直得不到执行。
  2. 公平调度:使用一个计数器记录写操作等待的次数或者时间,当达到一定阈值时,优先处理写操作。

示例代码

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()
}

在上述代码中:

  1. writeCh 用于标识是否有写操作在等待。
  2. 读操作在加读锁前,通过 select 语句检查是否有写操作在等待,如果有则先让出资源,等待写操作完成。
  3. 写操作通过 writeCh 来控制,确保每次只有一个写操作在进行,并且在读操作发现有写操作等待时,读操作会等待写操作完成。这样可以有效避免写饥饿现象。