From 9f5e1686397ffcd35b14ef25e48f1d7e3f2e1ea8 Mon Sep 17 00:00:00 2001 From: mogemimi Date: Wed, 18 Sep 2024 01:00:29 +0900 Subject: [PATCH] Improve spin lock for C++20 --- pomdog/utility/spin_lock.cpp | 34 +++++++++++----------------------- pomdog/utility/spin_lock.h | 9 ++------- 2 files changed, 13 insertions(+), 30 deletions(-) diff --git a/pomdog/utility/spin_lock.cpp b/pomdog/utility/spin_lock.cpp index 02facae11..d18f00664 100644 --- a/pomdog/utility/spin_lock.cpp +++ b/pomdog/utility/spin_lock.cpp @@ -1,16 +1,6 @@ // Copyright mogemimi. Distributed under the MIT license. #include "pomdog/utility/spin_lock.h" -#include "pomdog/basic/conditional_compilation.h" -#include "pomdog/basic/platform.h" - -POMDOG_SUPPRESS_WARNINGS_GENERATED_BY_STD_HEADERS_BEGIN -#if defined(POMDOG_PLATFORM_LINUX) && (defined(__x86_64__) || defined(_M_X64) || defined(_M_AMD64)) -#include -#else -#include -#endif -POMDOG_SUPPRESS_WARNINGS_GENERATED_BY_STD_HEADERS_END namespace pomdog::detail { @@ -18,24 +8,22 @@ SpinLock::SpinLock() noexcept = default; void SpinLock::lock() noexcept { - while (flag.test_and_set(std::memory_order_acquire)) { -#if defined(POMDOG_PLATFORM_LINUX) && (defined(__x86_64__) || defined(_M_X64) || defined(_M_AMD64)) - // NOTE: For both performance and power consumption, we use the - // pause instruction in the loop instead of fully spinning. - // https://software.intel.com/en-us/articles/benefitting-power-and-performance-sleep-loops/ - // http://open-std.org/JTC1/SC22/WG21/docs/papers/2016/p0514r0.pdf - _mm_pause(); -#else - // NOTE: It is much faster to use `std::this_thread::yield()` than to - // call `_mm_pause()` directly on Windows and macOS. - std::this_thread::yield(); -#endif + while (flag_.test_and_set(std::memory_order_acquire)) { + // NOTE: Instead of a busy loop, a wait instruction is inserted + // to put the CPU into low power consumption mode. + // When implementing spin, it is possible to call the __mm_pause(), + // _umwait(), TPAUSE, or std::this_thread::yield(), but here wait() is called for portability. + // + // https://software.intel.com/en-us/articles/benefitting-power-and-performance-sleep-loops/ + // http://open-std.org/JTC1/SC22/WG21/docs/papers/2016/p0514r0.pdf + flag_.wait(true, std::memory_order_relaxed); } } void SpinLock::unlock() noexcept { - flag.clear(std::memory_order_release); + flag_.clear(std::memory_order_release); + flag_.notify_one(); } } // namespace pomdog::detail diff --git a/pomdog/utility/spin_lock.h b/pomdog/utility/spin_lock.h index dd5f68f76..b422dc9d4 100644 --- a/pomdog/utility/spin_lock.h +++ b/pomdog/utility/spin_lock.h @@ -12,13 +12,8 @@ POMDOG_SUPPRESS_WARNINGS_GENERATED_BY_STD_HEADERS_END namespace pomdog::detail { class POMDOG_EXPORT SpinLock final { -#if defined(__EMSCRIPTEN__) - // NOTE: for C++20 - std::atomic_flag flag; -#else - // NOTE: for C++17 - std::atomic_flag flag = ATOMIC_FLAG_INIT; -#endif + std::atomic_flag flag_; + static_assert(__cplusplus >= 202002L, "ATOMIC_FLAG_INIT was deprecated in C++20, https://cplusplus.github.io/LWG/issue3659"); public: SpinLock() noexcept;