提升原子引用计数示例是否包含错误?

Does boost atomic reference counting example contain a bug?

我指的是 this example。 作者使用 memory_order_release 来递减计数器。他们甚至在 the discussion section 中声明使用 memory_order_acq_rel 代替会过度。但是理论上下面的场景不会导致 x 永远不会被删除吗?

来自 link 的代码示例:

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

引自讨论部分:

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.

单个原子变量的所有修改都按照全局修改顺序进行。两个线程不可能不同意这个顺序。

fetch_sub操作是一个原子read-modify-write操作,要求总是从修改顺序中的同一个操作读取修改前的原子变量的值。

所以当第一个线程的 fetch_sub 在修改顺序中排在第一位时,第二个线程不可能读取 2。如果硬件本身不支持这种原子访问,则实现必须确保不会发生这种缓存不一致,必要时借助锁。 (这就是原子的 is_lock_freeis_always_lock_free 成员要检查的内容。)

这完全独立于操作的内存顺序。这些只对访问 other 内存位置比原子变量本身重要。