MST

星途 面试题库

面试题:Rust条件变量在复杂多线程场景下的同步优化

假设存在一个多线程程序,其中有多个读写线程操作一个共享数据结构。读线程只读取数据,写线程会修改数据。为了保证数据一致性,需要使用条件变量来优化同步机制。请详细说明如何设计这种同步方案,避免读写冲突和死锁,并且给出关键代码示例及对性能优化点的解释。
37.7万 热度难度
编程语言Rust

知识考点

AI 面试

面试题答案

一键面试

同步方案设计

  1. 数据结构与锁的选择
    • 使用互斥锁(std::mutex 在 C++ 中)来保护共享数据结构,确保同一时间只有一个线程可以访问它。
    • 使用条件变量(std::condition_variable 在 C++ 中)来协调读写线程的操作。
  2. 读线程逻辑
    • 读线程在读取数据前,先获取互斥锁。
    • 如果有写线程正在修改数据,读线程通过条件变量等待,直到写操作完成并通知读线程。
    • 读取数据后,释放互斥锁。
  3. 写线程逻辑
    • 写线程在修改数据前,先获取互斥锁。
    • 在修改数据前,检查是否有读线程正在读取数据,如果有,则等待读线程全部读完(通过条件变量通知读线程数据已修改)。
    • 修改数据后,通过条件变量通知所有等待的读线程。
    • 释放互斥锁。
  4. 避免死锁
    • 所有线程获取锁的顺序必须一致,避免出现循环等待的情况。
    • 对于条件变量的等待,要在持有互斥锁的情况下调用 wait 函数,wait 函数会自动释放互斥锁并等待,当被唤醒时会重新获取互斥锁。

关键代码示例(以 C++ 为例)

#include <iostream>
#include <thread>
#include <mutex>
#include <condition_variable>
#include <vector>

std::mutex mtx;
std::condition_variable cv;
bool data_ready = false;
int shared_data;

void read_thread() {
    std::unique_lock<std::mutex> lock(mtx);
    cv.wait(lock, []{ return data_ready; });
    std::cout << "Read data: " << shared_data << std::endl;
    data_ready = false;
}

void write_thread(int value) {
    std::unique_lock<std::mutex> lock(mtx);
    shared_data = value;
    data_ready = true;
    cv.notify_all();
}

int main() {
    std::vector<std::thread> threads;
    for (int i = 0; i < 3; ++i) {
        threads.emplace_back(read_thread);
    }
    for (int i = 0; i < 3; ++i) {
        threads.emplace_back(write_thread, i * 10);
    }
    for (auto& th : threads) {
        th.join();
    }
    return 0;
}

性能优化点解释

  1. 减少锁的持有时间
    • 读线程在读取数据后尽快释放互斥锁,写线程在修改数据并通知后尽快释放互斥锁,这样可以减少其他线程等待锁的时间,提高并发性能。
  2. 条件变量的使用
    • 条件变量使得读线程在数据未准备好时进入等待状态,避免了无效的忙等待,从而降低 CPU 占用率。同时,通过条件变量的通知机制,能够及时唤醒等待的线程,提高线程间的协作效率。
  3. 批量操作
    • 如果可能,尽量对共享数据进行批量读写操作,减少锁的获取和释放次数,进一步提高性能。例如,在写线程中可以一次性更新多个相关数据,然后统一通知读线程。