MST

星途 面试题库

面试题:C++类成员函数在复杂多线程场景下的数据竞争分析

有一个C++类 `ComplexClass`,它包含多个成员变量,如 `std::vector<int> vec;`、`std::mutex mtx;` 以及一个成员函数 `void addElement(int num)`。在 `addElement` 函数中,先对 `vec` 进行一些检查(比如 `if (vec.size() < 10)`),然后获取 `mtx` 锁,接着将 `num` 添加到 `vec` 中。现在有多个线程同时调用 `addElement` 函数,分析是否存在线程安全问题,如果存在,应该如何修改代码以确保线程安全?请详细说明分析过程和修改方法。
36.2万 热度难度
编程语言C++

知识考点

AI 面试

面试题答案

一键面试

分析

  1. 存在线程安全问题
    • addElement 函数中,if (vec.size() < 10) 检查和获取锁 mtx 这两个操作不是原子的。
    • 假设线程A检查到 vec.size() < 10,但在获取锁之前,线程B也进行了检查,同样发现 vec.size() < 10
    • 然后线程A获取锁并添加元素,接着线程B获取锁也添加元素,这样可能导致 vec 的元素数量超过10,违反了原本的设计意图。

修改方法

  1. 修改后的代码如下
#include <vector>
#include <mutex>

class ComplexClass {
private:
    std::vector<int> vec;
    std::mutex mtx;
public:
    void addElement(int num) {
        std::unique_lock<std::mutex> lock(mtx);
        if (vec.size() < 10) {
            vec.push_back(num);
        }
    }
};
  1. 解释
    • 使用 std::unique_lock<std::mutex> lock(mtx); 在函数开始就获取锁,这样在检查 vec.size() < 10 和添加元素 vec.push_back(num) 这两个操作过程中,其他线程无法访问 vec,从而确保了线程安全。
    • std::unique_lock 相较于直接使用 mtx.lock()mtx.unlock() 更加安全和灵活,它在析构时会自动释放锁,避免了因异常等情况导致锁未释放的问题。