Sil*_*ler 17 c++ multithreading atomic reference-counting c++11
我试图准确理解线程安全的原子引用计数是如何工作的,例如std::shared_ptr
.我的意思是,基本概念很简单,但我真的很担心减法加上如何delete
避免竞争条件.
Boost的这个教程演示了如何使用Boost原子库(或C++ 11原子库)实现原子线程安全的引用计数系统.
#include <boost/intrusive_ptr.hpp>
#include <boost/atomic.hpp>
class X {
public:
typedef boost::intrusive_ptr<X> pointer;
X() : refcount_(0) {}
private:
mutable boost::atomic<int> refcount_;
friend void intrusive_ptr_add_ref(const X * x)
{
x->refcount_.fetch_add(1, boost::memory_order_relaxed);
}
friend void intrusive_ptr_release(const X * x)
{
if (x->refcount_.fetch_sub(1, boost::memory_order_release) == 1) {
boost::atomic_thread_fence(boost::memory_order_acquire);
delete x;
}
}
};
Run Code Online (Sandbox Code Playgroud)
好的,所以我得到了一般的想法.但我不明白为什么以下情况不可能:
说refcount是当前的1
.
0
.1
.delete
托管对象指针.1
,访问托管对象指针... SEGFAULT!我无法理解是什么阻止了这种情况发生,因为在refcount达到0和删除对象之间没有任何阻止数据竞争的东西.减少引用计数和调用delete
是两个独立的非原子操作.那么没有锁定怎么可能呢?
Mik*_*eMB 22
您可能高估了shared_ptr提供的线程安全性.
原子引用计数的本质是确保如果访问/修改a的两个不同实例shared_ptr
(管理同一对象),则不存在竞争条件.但是,shared_ptr
如果两个线程访问同一个shared_ptr
对象(其中一个是写入),则不能确保线程安全.一个例子是,例如,如果一个线程解引用指针,而另一个线程重置它.
因此shared_ptr
,只要在shared_ptr的单个实例上没有竞争(它也不会访问指向线程安全的对象),唯一保证就是不会有双重删除和泄漏.
因此,创建shared_ptr的副本只是无竞争,如果没有其他线程,可以在逻辑上同时删除/重置它(你也可以说,它不是内部同步的).这是您描述的场景.
要再次重复:从多个线程访问单个 shared_ptr
实例, 其中一个访问是写入(指针)仍然是竞争条件.
如果您想以std::shared_ptr
线程安全方式复制,则必须确保所有加载和存储都通过std::atomic_...
专门的操作发生shared_ptr
.
归档时间: |
|
查看次数: |
6086 次 |
最近记录: |