代码之家  ›  专栏  ›  技术社区  ›  ZivS

具有std::shared_ptr的线程安全性

  •  0
  • ZivS  · 技术社区  · 6 年前

    我在读关于std::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和返回之间调用stop())。或者可以使用共享指针的锁定机制,而不使用此方法中的锁定:

       std::shared_ptr<int> get_obj() const
        {
            auto tmp = _obj;
            if(!tmp) throw std::exception();
            return tmp;
        }
    
    1 回复  |  直到 6 年前
        1
  •  2
  •   Alan Birtles    6 年前

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

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

    因此,您要么需要将互斥锁在 get_obj 方法或用途 std::atomic_load std::atomic_store 在你 start stop 方法