MST

星途 面试题库

面试题:C++中std::shared_ptr的基本线程安全场景

在C++中,std::shared_ptr在哪些常见操作下具有线程安全性?请举例说明并解释原因。
32.2万 热度难度
编程语言C++

知识考点

AI 面试

面试题答案

一键面试

1. 不同线程对std::shared_ptr对象的独立操作

  • 操作:不同线程对各自独立的std::shared_ptr对象进行创建、销毁、赋值等操作时是线程安全的。
  • 举例
#include <memory>
#include <thread>

void threadFunction1() {
    std::shared_ptr<int> ptr1 = std::make_shared<int>(10);
    // 对ptr1进行其他操作,如解引用等
}

void threadFunction2() {
    std::shared_ptr<int> ptr2 = std::make_shared<int>(20);
    // 对ptr2进行其他操作,如解引用等
}

int main() {
    std::thread t1(threadFunction1);
    std::thread t2(threadFunction2);
    t1.join();
    t2.join();
    return 0;
}
  • 原因:每个std::shared_ptr对象有自己独立的引用计数,不同线程操作不同的std::shared_ptr对象不会相互干扰,因此是线程安全的。

2. 多个线程对同一个std::shared_ptr对象的读操作

  • 操作:多个线程同时对同一个std::shared_ptr对象进行读操作(例如获取指向对象的指针或访问引用计数)是线程安全的。
  • 举例
#include <memory>
#include <iostream>
#include <thread>

std::shared_ptr<int> globalPtr;

void readSharedPtr() {
    std::cout << "Thread reads value: " << *(globalPtr.get()) << std::endl;
    std::cout << "Thread reads ref count: " << globalPtr.use_count() << std::endl;
}

int main() {
    globalPtr = std::make_shared<int>(42);
    std::thread t1(readSharedPtr);
    std::thread t2(readSharedPtr);
    t1.join();
    t2.join();
    return 0;
}
  • 原因std::shared_ptr的引用计数和指向对象的指针的读取操作通常是原子操作,多个线程同时读取不会导致数据竞争。

3. 多个线程对同一个std::shared_ptr对象的写操作

  • 操作:多个线程对同一个std::shared_ptr对象进行写操作(如赋值、reset等改变引用计数或指向对象的操作)不是线程安全的,需要额外的同步机制。
  • 举例
#include <memory>
#include <iostream>
#include <thread>

std::shared_ptr<int> globalPtr;

void writeSharedPtr() {
    globalPtr = std::make_shared<int>(10);
}

int main() {
    std::thread t1(writeSharedPtr);
    std::thread t2(writeSharedPtr);
    t1.join();
    t2.join();
    // 这里可能会出现未定义行为,因为没有同步机制
    std::cout << "Final ref count: " << globalPtr.use_count() << std::endl;
    return 0;
}
  • 原因:写操作会改变引用计数和指向对象的指针,多个线程同时进行写操作可能导致引用计数混乱或指针指向错误,从而引发未定义行为。若要保证线程安全,可使用std::mutex等同步机制:
#include <memory>
#include <iostream>
#include <thread>
#include <mutex>

std::shared_ptr<int> globalPtr;
std::mutex ptrMutex;

void writeSharedPtr() {
    std::lock_guard<std::mutex> lock(ptrMutex);
    globalPtr = std::make_shared<int>(10);
}

int main() {
    std::thread t1(writeSharedPtr);
    std::thread t2(writeSharedPtr);
    t1.join();
    t2.join();
    std::cout << "Final ref count: " << globalPtr.use_count() << std::endl;
    return 0;
}