title: Confusion about _Lock_policy in libstdc++
body: <p>I'm reading the implements of std::shared_ptr of libstdc++, and I noticed that libstdc++ has three locking policies: _S_single, _S_mutex, and _S_atomic (see <a href="https://github.com/gcc-mirror/gcc/blob/master/libstdc%2B%2B-v3/include/ext/concurrence.h#L49" rel="nofollow noreferrer">here</a>), and the lock policy would affect the specialization of class _Sp_counted_base (<a href="https://github.com/gcc-mirror/gcc/blob/master/libstdc%2B%2B-v3/include/bits/shared_ptr_base.h#L251" rel="nofollow noreferrer">_M_add_ref</a> and <a href="https://github.com/gcc-mirror/gcc/blob/master/libstdc%2B%2B-v3/include/bits/shared_ptr_base.h#L169" rel="nofollow noreferrer">_M_release</a>)</p>
  <p>Below is the code snippet：</p>
  <pre><code>_M_release_last_use() noexcept
  {
      _GLIBCXX_SYNCHRONIZATION_HAPPENS_AFTER(&amp;_M_use_count);
      _M_dispose();
      // There must be a memory barrier between dispose() and destroy()
      // to ensure that the effects of dispose() are observed in the
      // thread that runs destroy().
      // See http://gcc.gnu.org/ml/libstdc++/2005-11/msg00136.html
      if (_Mutex_base&lt;_Lp&gt;::_S_need_barriers)
      {
          __atomic_thread_fence (__ATOMIC_ACQ_REL);
      }
  
      // Be race-detector-friendly.  For more info see bits/c++config.
      _GLIBCXX_SYNCHRONIZATION_HAPPENS_BEFORE(&amp;_M_weak_count);
      if (__gnu_cxx::__exchange_and_add_dispatch(&amp;_M_weak_count,
                                                 -1) == 1)
      {
          _GLIBCXX_SYNCHRONIZATION_HAPPENS_AFTER(&amp;_M_weak_count);
          _M_destroy();
      }
    }
   
    template&lt;&gt;
    inline bool
    _Sp_counted_base&lt;_S_mutex&gt;::
    _M_add_ref_lock_nothrow() noexcept
    {
       __gnu_cxx::__scoped_lock sentry(*this);
      if (__gnu_cxx::__exchange_and_add_dispatch(&amp;_M_use_count, 1) == 0)
      {
           _M_use_count = 0;
           return false;
       }
       return true;
     }
  </code></pre>
  <p>my questions are:</p>
  <ol>
  <li>When using the _S_mutex locking policy, the __exchange_and_add_dispatch function may only guarantee atomicity, but may not guarantee that it is fully fenced, am I right?</li>
  <li>and because of 1, is the purpose of '__atomic_thread_fence (__ATOMIC_ACQ_REL)' to ensure that when thread A invoking _M_dispose, no thread will invoke _M_destory (so that thread A could never access a destroyed member(eg: _M_ptr) inside the function '_M_dispose'?</li>
  <li>What puzzles me most is that if 1 and 2 are both correct, then why there is no need to add a thread fence before invoking the '_M_dispose'? (because the objects managed by _Sp_counted_base and _Sp_counted_base itself have the same problem when the reference count is dropped to zero)</li>
  </ol>