2

In the example of boost::atomic, the unref function:

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

1: the fetch_sub op is limited by memory_order_release, which prevents preceding operations to be reordered past the point. But what are the possible scenes that would have such phenomenon?

2: in addition of memory_order_release on the atomic op, why there is an additional memory_order_acquire before the deletion?

curiousguy
  • 8,038
  • 2
  • 40
  • 58
jiandingzhe
  • 1,881
  • 15
  • 35
  • 1
    Try this question: http://stackoverflow.com/questions/16179938/c11-memory-order-acquire-and-memory-order-release-semantics – firda Aug 14 '14 at 09:17
  • 1
    This one seems better related: http://stackoverflow.com/questions/10268737/c11-atomics-and-intrusive-shared-pointer-reference-count?rq=1 – firda Aug 14 '14 at 09:21
  • `sub` is a RMW operation. – Kerrek SB Aug 14 '14 at 09:50

1 Answers1

1

For the first question, it prevents any use of (*x) to be reordered after the fetch_sub (when the reference count could be 0 and use is therefore banned). Possible causes are CPU reordering or compiler reordering. The second question is just the mirror of the release; release protects stores and acquire protects loads.

It may seem that refcount_fetch_sub(1, memory_order_acq_rel) works as well, but that protects just the refcount.

MSalters
  • 173,980
  • 10
  • 155
  • 350
  • I know both compiler and CPU may reorder commands. However, in this case, the `delete x` command is dependent on the result of the `fetch_sub`. Why there are still possibility that things in `delete x` may be reordered prior to `fetch_sub`? – jiandingzhe Aug 21 '14 at 05:55
  • 1
    In a single-threaded view, reads could be reordered before an unrelated write, i.e. the other members of `x` may already be read to prevent a pipeline stall if the branch succeeds. And that in turn may cause the deletion of an older version of `x` when another thread had updated `x`. – MSalters Aug 21 '14 at 07:06
  • "_but that protects just the refcount._" What do you mean? – curiousguy Nov 26 '19 at 22:10
  • Surely `memory_order_acq_rel` doesn't just protect the refcount? Rather the separate barrier is used as an optimization, so that it only uses an acquire barrier if the reference count reaches 0? – rdb Jan 26 '22 at 23:44