File indexing completed on 2025-01-30 09:35:34
0001
0002
0003
0004
0005
0006
0007 #ifndef BOOST_FIBERS_SPINLOCK_TTAS_ADAPTIVE_H
0008 #define BOOST_FIBERS_SPINLOCK_TTAS_ADAPTIVE_H
0009
0010 #include <algorithm>
0011 #include <atomic>
0012 #include <chrono>
0013 #include <cmath>
0014 #include <random>
0015 #include <thread>
0016
0017 #include <boost/fiber/detail/config.hpp>
0018 #include <boost/fiber/detail/cpu_relax.hpp>
0019 #include <boost/fiber/detail/spinlock_status.hpp>
0020
0021
0022
0023
0024
0025 namespace boost {
0026 namespace fibers {
0027 namespace detail {
0028
0029 class spinlock_ttas_adaptive {
0030 private:
0031 template< typename FBSplk >
0032 friend class spinlock_rtm;
0033
0034 std::atomic< spinlock_status > state_{ spinlock_status::unlocked };
0035 std::atomic< std::size_t > retries_{ 0 };
0036
0037 public:
0038 spinlock_ttas_adaptive() = default;
0039
0040 spinlock_ttas_adaptive( spinlock_ttas_adaptive const&) = delete;
0041 spinlock_ttas_adaptive & operator=( spinlock_ttas_adaptive const&) = delete;
0042
0043 void lock() noexcept {
0044 static thread_local std::minstd_rand generator{ std::random_device{}() };
0045 std::size_t collisions = 0 ;
0046 for (;;) {
0047 std::size_t retries = 0;
0048 const std::size_t prev_retries = retries_.load( std::memory_order_relaxed);
0049 const std::size_t max_relax_retries = (std::min)(
0050 static_cast< std::size_t >( BOOST_FIBERS_SPIN_BEFORE_SLEEP0), 2 * prev_retries + 10);
0051 const std::size_t max_sleep_retries = (std::min)(
0052 static_cast< std::size_t >( BOOST_FIBERS_SPIN_BEFORE_YIELD), 2 * prev_retries + 10);
0053
0054
0055
0056
0057
0058
0059
0060
0061
0062
0063 while ( spinlock_status::locked == state_.load( std::memory_order_relaxed) ) {
0064 #if !defined(BOOST_FIBERS_SPIN_SINGLE_CORE)
0065 if ( max_relax_retries > retries) {
0066 ++retries;
0067
0068
0069
0070
0071
0072 cpu_relax();
0073 } else if ( max_sleep_retries > retries) {
0074 ++retries;
0075
0076
0077
0078
0079 static constexpr std::chrono::microseconds us0{ 0 };
0080 std::this_thread::sleep_for( us0);
0081 } else {
0082
0083
0084
0085 std::this_thread::yield();
0086 }
0087 #else
0088 std::this_thread::yield();
0089 #endif
0090 }
0091
0092
0093 if ( spinlock_status::locked == state_.exchange( spinlock_status::locked, std::memory_order_acquire) ) {
0094
0095
0096
0097 std::uniform_int_distribution< std::size_t > distribution{
0098 0, static_cast< std::size_t >( 1) << (std::min)(collisions, static_cast< std::size_t >( BOOST_FIBERS_CONTENTION_WINDOW_THRESHOLD)) };
0099 const std::size_t z = distribution( generator);
0100 ++collisions;
0101 for ( std::size_t i = 0; i < z; ++i) {
0102
0103
0104 cpu_relax();
0105 }
0106 } else {
0107 retries_.store( prev_retries + (retries - prev_retries) / 8, std::memory_order_relaxed);
0108
0109 break;
0110 }
0111 }
0112 }
0113
0114 bool try_lock() noexcept {
0115 return spinlock_status::unlocked == state_.exchange( spinlock_status::locked, std::memory_order_acquire);
0116 }
0117
0118 void unlock() noexcept {
0119 state_.store( spinlock_status::unlocked, std::memory_order_release);
0120 }
0121 };
0122
0123 }}}
0124
0125 #endif