MST

星途 面试题库

面试题:自定义Rust读写锁及其性能特性优化

假设Rust标准库中不存在读写锁(`RwLock`),请你基于底层的同步原语(如`Mutex`、`Condvar`等)实现一个自定义的读写锁。在实现过程中,要考虑性能优化,例如如何减少锁争用,如何在高并发读场景下提升吞吐量。实现后,请分析你实现的读写锁在不同读写比例场景下的性能特性。
46.7万 热度难度
编程语言Rust

知识考点

AI 面试

面试题答案

一键面试
use std::sync::{Arc, Condvar, Mutex};

struct MyRwLock<T> {
    data: T,
    readers_count: usize,
    writers_waiting: usize,
    mutex: Mutex<()>,
    read_cv: Condvar,
    write_cv: Condvar,
}

impl<T> MyRwLock<T> {
    fn new(data: T) -> Self {
        MyRwLock {
            data,
            readers_count: 0,
            writers_waiting: 0,
            mutex: Mutex::new(()),
            read_cv: Condvar::new(),
            write_cv: Condvar::new(),
        }
    }

    fn read(&self) -> ReadGuard<'_, T> {
        let mut lock = self.mutex.lock().unwrap();
        while self.writers_waiting > 0 {
            lock = self.read_cv.wait(lock).unwrap();
        }
        self.readers_count += 1;
        drop(lock);
        ReadGuard {
            rwlock: self,
        }
    }

    fn write(&self) -> WriteGuard<'_, T> {
        let mut lock = self.mutex.lock().unwrap();
        self.writers_waiting += 1;
        while self.readers_count > 0 || self.writers_waiting > 1 {
            lock = self.write_cv.wait(lock).unwrap();
        }
        self.writers_waiting -= 1;
        WriteGuard {
            rwlock: self,
        }
    }
}

struct ReadGuard<'a, T> {
    rwlock: &'a MyRwLock<T>,
}

impl<'a, T> Drop for ReadGuard<'a, T> {
    fn drop(&mut self) {
        let mut lock = self.rwlock.mutex.lock().unwrap();
        self.rwlock.readers_count -= 1;
        if self.rwlock.readers_count == 0 {
            self.rwlock.write_cv.notify_one();
        } else {
            self.rwlock.read_cv.notify_one();
        }
    }
}

struct WriteGuard<'a, T> {
    rwlock: &'a MyRwLock<T>,
}

impl<'a, T> Drop for WriteGuard<'a, T> {
    fn drop(&mut self) {
        let mut lock = self.rwlock.mutex.lock().unwrap();
        self.rwlock.write_cv.notify_all();
        self.rwlock.read_cv.notify_all();
    }
}

// 性能分析
### 高读场景
- **性能特性**:由于读操作不互斥,只要没有写操作在进行或等待,多个读操作可以同时进行。减少了锁争用,吞吐量较高。当读操作远远多于写操作时,性能接近无锁状态下的并发读性能。
### 高写场景
- **性能特性**:写操作需要独占锁,并且在等待写操作时,读操作也会被阻塞。随着写操作比例增加,锁争用加剧,吞吐量下降,因为每次写操作都要等待所有读操作完成,并且其他写操作也要排队等待。
### 读写均衡场景
- **性能特性**:性能介于高读和高写场景之间。读操作会因为写操作的等待而偶尔被阻塞,写操作也会因为读操作的进行而等待。合理的同步机制(如使用条件变量通知)在一定程度上缓解锁争用,但整体性能会受到读写操作相互影响的制约。