MST

星途 面试题库

面试题:C++中std::shared_ptr的线程安全问题

在多线程环境下使用std::shared_ptr可能会遇到哪些线程安全问题?如何解决这些问题?请举例说明。
29.3万 热度难度
编程语言C++

知识考点

AI 面试

面试题答案

一键面试

可能遇到的线程安全问题

  1. 引用计数更新问题:多个线程同时访问和修改 std::shared_ptr 的引用计数时,可能会导致数据竞争。例如,一个线程正在增加引用计数,另一个线程同时减少引用计数,这可能会导致引用计数出现不一致的情况,最终可能导致对象被提前释放或内存泄漏。
  2. 对象访问问题:当一个线程正在访问 std::shared_ptr 指向的对象,而另一个线程释放了该对象(通过将 std::shared_ptr 的引用计数减为 0),那么访问对象的线程可能会访问到已释放的内存,导致未定义行为。

解决方法

  1. 使用互斥锁(Mutex)
    • 原理:通过互斥锁来保护对 std::shared_ptr 的操作,确保同一时间只有一个线程可以访问和修改 std::shared_ptr
    • 示例代码:
#include <iostream>
#include <memory>
#include <mutex>
#include <thread>

std::mutex mtx;
std::shared_ptr<int> sharedData;

void threadFunction() {
    std::lock_guard<std::mutex> lock(mtx);
    if (!sharedData) {
        sharedData = std::make_shared<int>(42);
    }
    std::cout << "Thread sees value: " << *sharedData << std::endl;
}

int main() {
    std::thread t1(threadFunction);
    std::thread t2(threadFunction);

    t1.join();
    t2.join();

    return 0;
}
  1. 使用 std::atomic_shared_ptr(C++20 及以上)
    • 原理:std::atomic_shared_ptr 提供了原子操作语义,确保对 std::shared_ptr 的各种操作(如赋值、比较、释放等)是线程安全的,无需额外的锁。
    • 示例代码:
#include <iostream>
#include <memory>
#include <atomic>
#include <thread>

std::atomic_shared_ptr<int> atomicSharedData;

void threadFunction() {
    auto localPtr = atomicSharedData.load();
    if (!localPtr) {
        localPtr = std::make_shared<int>(42);
        atomicSharedData.store(localPtr);
    }
    std::cout << "Thread sees value: " << *localPtr << std::endl;
}

int main() {
    std::thread t1(threadFunction);
    std::thread t2(threadFunction);

    t1.join();
    t2.join();

    return 0;
}
  1. 使用线程本地存储(Thread - Local Storage,TLS)
    • 原理:每个线程都有自己独立的 std::shared_ptr 副本,避免了多个线程对同一个 std::shared_ptr 的竞争。但是,这种方法适用于每个线程需要独立处理对象的场景,不适合线程间需要共享对象状态的情况。
    • 示例代码:
#include <iostream>
#include <memory>
#include <thread>
#include <thread>

thread_local std::shared_ptr<int> localSharedData;

void threadFunction() {
    if (!localSharedData) {
        localSharedData = std::make_shared<int>(42);
    }
    std::cout << "Thread sees value: " << *localSharedData << std::endl;
}

int main() {
    std::thread t1(threadFunction);
    std::thread t2(threadFunction);

    t1.join();
    t2.join();

    return 0;
}