From 702c5756d5a2050327603cb9e507c839f928a7a3 Mon Sep 17 00:00:00 2001 From: Boris Kolpackov Date: Mon, 6 Nov 2017 13:44:46 +0200 Subject: Make shared_base counter atomic in C++11 and up --- odb/details/shared-ptr/base.cxx | 11 ----------- odb/details/shared-ptr/base.hxx | 15 ++++++++++----- odb/details/shared-ptr/base.ixx | 26 +++++++++++++++++++++----- 3 files changed, 31 insertions(+), 21 deletions(-) diff --git a/odb/details/shared-ptr/base.cxx b/odb/details/shared-ptr/base.cxx index e03d76e..77a571e 100644 --- a/odb/details/shared-ptr/base.cxx +++ b/odb/details/shared-ptr/base.cxx @@ -26,17 +26,6 @@ namespace odb return new not_shared (*this); } - bool shared_base:: - _dec_ref_callback () - { - bool r (--counter_ == 0); - - if (r) - r = callback_->zero_counter (callback_->arg); - - return r; - } - namespace bits { size_t* locator_common:: diff --git a/odb/details/shared-ptr/base.hxx b/odb/details/shared-ptr/base.hxx index c042fa6..5153aba 100644 --- a/odb/details/shared-ptr/base.hxx +++ b/odb/details/shared-ptr/base.hxx @@ -7,10 +7,15 @@ #include +#include // ODB_CXX11, ODB_NOTHROW_NOEXCEPT + #include #include // std::size_t -#include // ODB_CXX11, ODB_NOTHROW_NOEXCEPT +#ifdef ODB_CXX11 +#include +#endif + #include #include @@ -96,12 +101,12 @@ namespace odb bool (*zero_counter) (void*); }; - private: - bool - _dec_ref_callback (); - protected: +#ifdef ODB_CXX11 + std::atomic counter_; +#else std::size_t counter_; +#endif refcount_callback* callback_; }; diff --git a/odb/details/shared-ptr/base.ixx b/odb/details/shared-ptr/base.ixx index 64bc88c..16207e1 100644 --- a/odb/details/shared-ptr/base.ixx +++ b/odb/details/shared-ptr/base.ixx @@ -45,22 +45,38 @@ namespace odb inline void shared_base:: _inc_ref () { - counter_++; +#ifdef ODB_CXX11 + counter_.fetch_add (1, std::memory_order_relaxed); +#else + ++counter_; +#endif } inline bool shared_base:: _dec_ref () { - if (callback_ == 0) - return --counter_ == 0; - else - return _dec_ref_callback (); + // While there are ways to avoid acquire (which is unnecessary except + // when the counter drops to zero), for our use-cases we'd rather keep + // it simple. + // + return +#ifdef ODB_CXX11 + counter_.fetch_sub (1, std::memory_order_acq_rel) == 1 +#else + --counter_ == 0 +#endif + ? callback_ == 0 || callback_->zero_counter (callback_->arg) + : false; } inline std::size_t shared_base:: _ref_count () const { +#ifdef ODB_CXX11 + return counter_.load (std::memory_order_relaxed); +#else return counter_; +#endif } #ifdef ODB_CXX11 -- cgit v1.1