使用std :: shared_ptr进行线程安全

时间:2019-01-13 17:55:47

标签: c++ c++11 thread-safety shared-ptr race-condition

我正在阅读有关std :: shared_ptr的线程安全性及其所提供的原子操作重载的信息,并且想知道类中特定的用例。

根据我对shared_ptr所承诺的线程安全性的理解,拥有这样的get方法是安全的:

class MyClass 
{
std::shared_ptr<int> _obj;
public:
    void start() 
    {
        std::lock_guard<std::mutex> lock(_mtx);
        _obj = std::make_shared<int>(1);
    }

    void stop()
    {
          std::lock_guard<std::mutex> lock(_mtx);
        _obj.reset();

    }
    std::shared_ptr<int> get_obj() const
    {
        return _obj; //Safe (?)
    }
};

getter应该是安全的,因为该对象将在任何线程的任何位置被初始化或为空。

但是如果我想在对象为空的情况下引发异常该怎么办,我需要在返回它之前对其进行检查,我现在必须在这里放置一个锁吗(因为可能在if和return之间调用stop()) )?还是可以使用共享指针的锁定机制而不在此方法中使用锁:

   std::shared_ptr<int> get_obj() const
    {
        auto tmp = _obj;
        if(!tmp) throw std::exception();
        return tmp;
    }

1 个答案:

答案 0 :(得分:2)

std::shared_ptr实例不是线程安全的。可以从多个线程修改都指向同一对象的多个实例,但是单个实例不是线程安全的。参见https://en.cppreference.com/w/cpp/memory/shared_ptr

  

所有成员函数(包括副本构造函数和副本分配)可以由shared_ptr的不同实例上的多个线程调用,而无需额外同步,即使这些实例是副本并共享同一对象的所有权。如果多个执行线程在不同步的情况下访问同一个shared_ptr,并且这些访问中的任何一个都使用了shared_ptr的非常量成员函数,则将发生数据争用;否则,将导致数据争用。原子函数的shared_ptr重载可用于防止数据争用。

因此,您需要在get_obj方法中锁定互斥锁,或者在std::atomic_loadstd::atomic_store方法中使用startstop