You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

C++智能指针能否从严格意义上避免data race?相关疑问及场景咨询

C++智能指针与数据竞争的关系

核心结论

C++的智能指针(包括std::shared_ptr和std::unique_ptr)本身无法从严格意义上避免数据竞争。它们的设计核心是管理堆对象的生命周期,而非解决多线程对指向对象的访问同步问题。

针对两种智能指针的具体说明

  • std::shared_ptr:它的引用计数操作是原子性的,多线程间增减引用计数不会引发数据竞争,但这仅保护了指针自身的生命周期管理。如果多个shared_ptr指向同一个对象,多线程对该对象的读写操作(比如你提到的访问次数更新/读取)仍然会产生race condition,因为智能指针不会对指向对象的访问做同步限制。
  • std::unique_ptr:它通过独占所有权机制确保同一时间只有一个unique_ptr指向对象,但这同样不代表指向对象的访问是线程安全的。如果通过裸指针、引用把对象地址传递给其他线程,或者在转移所有权时未做好同步,依然会出现数据竞争问题。

解决全局标志/共享数值的数据竞争方案

对于你提到的全局标志、堆上共享数值(如访问次数)这类场景,智能指针无法解决问题,需要借助专门的同步机制:

  1. 原子类型:对于布尔、整型这类简单数据,使用std::atomic<T>(如std::atomic<int>、std::atomic<bool>)是最优选择。原子类型的读写操作本身就是线程安全的,无需额外加锁。
  2. 互斥锁:如果涉及复杂对象或多步操作的同步,使用std::mutex配合std::lock_guard或std::unique_lock来包裹读写逻辑,确保同一时间只有一个线程访问共享资源。

示例场景的解决方案

针对你提到的"线程更新访问次数、线程定期读取日志"的场景,分别提供两种实现:

方案1:使用原子类型

#include <atomic>
#include <thread>
#include <iostream>
#include <chrono>

std::atomic<int> visit_count(0);

// 服务访客的线程函数:原子自增访问次数
void serve_visitor() {
    for (int i = 0; i < 1000; ++i) {
        visit_count.fetch_add(1, std::memory_order_relaxed);
        std::this_thread::sleep_for(std::chrono::microseconds(10));
    }
}

// 日志线程函数:原子读取当前访问次数
void log_visits() {
    for (int i = 0; i < 10; ++i) {
        int current = visit_count.load(std::memory_order_relaxed);
        std::cout << "当前访问次数:" << current << std::endl;
        std::this_thread::sleep_for(std::chrono::seconds(1));
    }
}

int main() {
    std::thread t1(serve_visitor);
    std::thread t2(log_visits);
    t1.join();
    t2.join();
    return 0;
}

方案2:使用互斥锁

#include <mutex>
#include <thread>
#include <iostream>
#include <chrono>

int visit_count = 0;
std::mutex mtx;

// 服务访客的线程函数:加锁后更新访问次数
void serve_visitor() {
    for (int i = 0; i < 1000; ++i) {
        std::lock_guard<std::mutex> lock(mtx);
        visit_count++;
        std::this_thread::sleep_for(std::chrono::microseconds(10));
    }
}

// 日志线程函数:加锁后读取访问次数
void log_visits() {
    for (int i = 0; i < 10; ++i) {
        std::lock_guard<std::mutex> lock(mtx);
        int current = visit_count;
        std::cout << "当前访问次数:" << current << std::endl;
        std::this_thread::sleep_for(std::chrono::seconds(1));
    }
}

int main() {
    std::thread t1(serve_visitor);
    std::thread t2(log_visits);
    t1.join();
    t2.join();
    return 0;
}

内容的提问来源于stack exchange,提问作者George Y

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.18 04:35:36