gpt4 book ai didi

c++ - 为什么在删除原子引用计数智能指针中的数据之前需要获取屏障?

转载 作者:可可西里 更新时间:2023-11-01 16:38:10 26 4
gpt4 key购买 nike

Boost 提供了一个 sample atomically reference counted shared pointer

这里是相关的代码片段和对使用的各种顺序的解释:

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;
}
}
};

Increasing the reference counter can always be done with memory_order_relaxed: New references to an object can only be formed from an existing reference, and passing an existing reference from one thread to another must already provide any required synchronization.

It is important to enforce any possible access to the object in one thread (through an existing reference) to happen before deleting the object in a different thread. This is achieved by a "release" operation after dropping a reference (any access to the object through this reference must obviously happened before), and an "acquire" operation before deleting the object.

It would be possible to use memory_order_acq_rel for the fetch_sub operation, but this results in unneeded "acquire" operations when the reference counter does not yet reach zero and may impose a performance penalty.

我无法理解为什么在 delete x 操作之前需要 memory_order_acquire 屏障。具体来说,编译器/处理器如何在fetch_sub之前对delete x的内存操作重新排序以及对x == 1的值的测试是如何安全的 不违反单线程语义?

编辑 我想,我的问题不是很清楚。这是改写后的版本:

读取 x (x->refcount_.fetch_sub(1, boost::memory_order_release) == 1) 和 delete x 操作之间的控制依赖关系提供任何订购保证吗?即使考虑单线程程序,编译器/处理器是否有可能在fetch_sub和比较之前对delete x操作对应的指令重新排序?如果答案尽可能低级并包括一个示例场景,其中删除操作被重新排序(不影响单线程语义)从而说明保留顺序的必要性,那将非常有帮助。

最佳答案

考虑两个线程,每个线程持有对对象的一个​​引用,这是最后两个引用:

------------------------------------------------------------
Thread 1 Thread 2
------------------------------------------------------------
// play with x here

fetch_sub(...)
fetch_sub(...)
// nothing
delete x;

您必须确保线程 1 在 //play with x here 中对对象所做的任何更改在线程 2 调用 delete x; 时可见。为此,您需要一个获取栅栏,它与 fetch_sub() 调用上的 memory_order_release 一起,保证线程 1 所做的更改可见。

关于c++ - 为什么在删除原子引用计数智能指针中的数据之前需要获取屏障?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/27751025/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com