diff --git a/include/spdlog/details/registry-inl.h b/include/spdlog/details/registry-inl.h index 596a11c5..01760b89 100644 --- a/include/spdlog/details/registry-inl.h +++ b/include/spdlog/details/registry-inl.h @@ -30,7 +30,7 @@ namespace spdlog { namespace details { -registry* registry::s_instance = nullptr; +std::atomic registry::s_instance{nullptr}; std::mutex registry::s_instanceMutex; SPDLOG_INLINE registry::registry() @@ -247,12 +247,22 @@ SPDLOG_INLINE void registry::free() { s_instance = nullptr; } -SPDLOG_INLINE registry ®istry::instance() { - std::lock_guard lock(s_instanceMutex); - if (s_instance == nullptr) { - s_instance = new registry(); +// Double checked locking to avoid expensive locks when not required. +// 1) First we atomically check if the instance is valid; in this case it can safely be returned directly without locking. +// 2) If the instance is actually null, then we can no longer perform the operation atomically, so need to lock the mutex. This will happen only once in the program's lifetime. One the mutex is locked, check if the instance is still null +// (as another thread might have changed it by this point). If it's still null, allocate and update the atomic instance pointer, unlock mutex and return the reference. +// https://preshing.com/20130930/double-checked-locking-is-fixed-in-cpp11/ +SPDLOG_INLINE registry ®istry::instance() { + auto *instance = s_instance.load(); + if (instance == nullptr) { + std::lock_guard lock(s_instanceMutex); + instance = s_instance.load(); + if (instance == nullptr) { + instance = new registry(); + s_instance.store(instance); + } } - return *s_instance; + return *instance; } SPDLOG_INLINE void registry::apply_logger_env_levels(std::shared_ptr new_logger) { diff --git a/include/spdlog/details/registry.h b/include/spdlog/details/registry.h index 46c103e4..71e26258 100644 --- a/include/spdlog/details/registry.h +++ b/include/spdlog/details/registry.h @@ -116,7 +116,7 @@ private: bool automatic_registration_ = true; size_t backtrace_n_messages_ = 0; - static registry* s_instance; + static std::atomic s_instance; static std::mutex s_instanceMutex; };