#ifndef ASYNC_MQTT5_SPINLOCK_HPP #define ASYNC_MQTT5_SPINLOCK_HPP #include namespace async_mqtt5::detail { #if defined(_MSC_VER) /* prefer using intrinsics directly instead of winnt.h macro */ /* http://software.intel.com/en-us/forums/topic/296168 */ //#include #if defined(_M_AMD64) || defined(_M_IX86) #pragma intrinsic(_mm_pause) #define __pause() _mm_pause() /* (if pause not supported by older x86 assembler, "rep nop" is equivalent)*/ /*#define __pause() __asm rep nop */ #elif defined(_M_IA64) #pragma intrinsic(__yield) #define __pause() __yield() #else #define __pause() YieldProcessor() #endif #elif defined(__x86_64__) || defined(__i386__) #define __pause() __asm__ __volatile__ ("pause") #elif defined(__arm__) || defined(__arm64__) || defined(__aarch64__) #define __pause() __asm__ __volatile__ ("yield") #endif // https://rigtorp.se/spinlock/ class spinlock { std::atomic lock_ { false }; public: void lock() noexcept { for (;;) { // Optimistically assume the lock is free on the first try if (!lock_.exchange(true, std::memory_order_acquire)) return; // Wait for lock to be released without generating cache misses while (lock_.load(std::memory_order_relaxed)) __pause(); } } bool try_lock() noexcept { // First do a relaxed load to check if lock is free in order to prevent // unnecessary cache misses if someone does while(!try_lock()) return !lock_.load(std::memory_order_relaxed) && !lock_.exchange(true, std::memory_order_acquire); } void unlock() noexcept { lock_.store(false, std::memory_order_release); } }; } // end namespace async_mqtt5::detail #endif // !ASYNC_MQTT5_SPINLOCK_HPP