在以下C++多线程示例中是否需要同步机制?
先看cppreference的这段描述:
所有成员函数(包括拷贝构造函数和拷贝赋值运算符)都可以由多个线程在不同的shared_ptr实例上调用,无需额外同步,即使这些实例是副本且共享同一对象的所有权。
你对这段描述的理解错在了范围——它只保证shared_ptr自身的操作是线程安全的,和它指向的对象无关。
核心区别
- shared_ptr自身的线程安全:多个线程对不同的shared_ptr实例(共享同一对象所有权)执行拷贝、赋值、调用
use_count()/reset()等成员函数时,不需要额外同步,因为它内部的引用计数操作是原子实现的,不会出现竞态问题。 - 指向对象的线程安全:shared_ptr不会给它指向的对象自动添加同步机制。当多个线程通过不同的shared_ptr实例访问、修改该对象的成员时,必须自己处理同步,否则会出现竞态条件,导致数据错误或输出混乱。
你的代码问题分析
你提供的代码中,三个线程通过不同的shared_ptr实例调用fun1/fun2/fun3,这些函数都在修改Demo::Value,并且直接向cout输出(cout无同步的多线程访问也会导致输出混乱)。这属于典型的无同步共享数据修改,必然出现随机的输出和错误的Value计算结果。
修正后的代码示例
给共享资源加上互斥锁,保证同一时间只有一个线程能修改Value和输出:
#include <iostream> #include <memory> #include <thread> #include <mutex> using namespace std; class Demo { public: int Value; std::mutex mtx; // 互斥锁,保护共享资源 Demo():Value(10){} void fun1() { for(int i=0; i<300000; i++) { std::lock_guard<std::mutex> lock(mtx); // 自动加锁/解锁,避免死锁 Value = Value + i; std::cout << "Value1 :" << Value << std::endl; } } void fun2() { for(int i=0; i<300000; i++) { std::lock_guard<std::mutex> lock(mtx); Value = Value + i; std::cout << "Value2 :" << Value << std::endl; } } void fun3() { for(int i=0; i<300000; i++) { std::lock_guard<std::mutex> lock(mtx); Value = Value + i; std::cout << "Value3 :" << Value << std::endl; } } }; int main() { std::shared_ptr<Demo> ptr1(new Demo); std::thread t1(&Demo::fun1, ptr1); std::shared_ptr<Demo> ptr2(ptr1); std::thread t2(&Demo::fun2, ptr2); std::shared_ptr<Demo> ptr3(ptr2); std::thread t3(&Demo::fun3, ptr3); t1.join(); t2.join(); t3.join(); }
修正后,每个线程进入修改Value和输出的临界区时会独占锁,避免了竞态条件,输出会有序,Value的计算结果也会正确。
内容的提问来源于stack exchange,提问作者Mangy
相关产品推荐
相关产品推荐

