我正在阅读有关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;
}
答案 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_load
和std::atomic_store
方法中使用start
和stop