mirror of
https://github.com/boostorg/unordered.git
synced 2025-07-31 03:47:16 +02:00
Change the backoff algorithm of rw_spinlock
This commit is contained in:
@ -30,8 +30,44 @@ private:
|
|||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
// number of times to spin before sleeping
|
// Effects: Provides a hint to the implementation that the current thread
|
||||||
static constexpr int spin_count = 24576;
|
// has been unable to make progress for k+1 iterations.
|
||||||
|
|
||||||
|
static void yield( unsigned k ) noexcept
|
||||||
|
{
|
||||||
|
unsigned const sleep_every = 1024; // see below
|
||||||
|
|
||||||
|
k %= sleep_every;
|
||||||
|
|
||||||
|
if( k < 5 )
|
||||||
|
{
|
||||||
|
// Intel recommendation from the Optimization Reference Manual
|
||||||
|
// Exponentially increase number of PAUSE instructions each
|
||||||
|
// iteration until reaching a maximum which is approximately
|
||||||
|
// one timeslice long (2^4 == 16 in our case)
|
||||||
|
|
||||||
|
unsigned const pause_count = 1 << k;
|
||||||
|
|
||||||
|
for( unsigned i = 0; i < pause_count; ++i )
|
||||||
|
{
|
||||||
|
boost::core::sp_thread_pause();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if( k < sleep_every - 1 )
|
||||||
|
{
|
||||||
|
// Once the maximum number of PAUSE instructions is reached,
|
||||||
|
// we switch to yielding the timeslice immediately
|
||||||
|
|
||||||
|
boost::core::sp_thread_yield();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// After `sleep_every` iterations of no progress, we sleep,
|
||||||
|
// to avoid a deadlock if a lower priority thread has the lock
|
||||||
|
|
||||||
|
boost::core::sp_thread_sleep();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
@ -51,9 +87,7 @@ public:
|
|||||||
|
|
||||||
void lock_shared() noexcept
|
void lock_shared() noexcept
|
||||||
{
|
{
|
||||||
for( ;; )
|
for( unsigned k = 0; ; ++k )
|
||||||
{
|
|
||||||
for( int k = 0; k < spin_count; ++k )
|
|
||||||
{
|
{
|
||||||
std::uint32_t st = state_.load( std::memory_order_relaxed );
|
std::uint32_t st = state_.load( std::memory_order_relaxed );
|
||||||
|
|
||||||
@ -63,10 +97,7 @@ public:
|
|||||||
if( state_.compare_exchange_weak( st, newst, std::memory_order_acquire, std::memory_order_relaxed ) ) return;
|
if( state_.compare_exchange_weak( st, newst, std::memory_order_acquire, std::memory_order_relaxed ) ) return;
|
||||||
}
|
}
|
||||||
|
|
||||||
boost::core::sp_thread_pause();
|
yield( k );
|
||||||
}
|
|
||||||
|
|
||||||
boost::core::sp_thread_sleep();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -102,9 +133,7 @@ public:
|
|||||||
|
|
||||||
void lock() noexcept
|
void lock() noexcept
|
||||||
{
|
{
|
||||||
for( ;; )
|
for( unsigned k = 0; ; ++k )
|
||||||
{
|
|
||||||
for( int k = 0; k < spin_count; ++k )
|
|
||||||
{
|
{
|
||||||
std::uint32_t st = state_.load( std::memory_order_relaxed );
|
std::uint32_t st = state_.load( std::memory_order_relaxed );
|
||||||
|
|
||||||
@ -131,44 +160,7 @@ public:
|
|||||||
state_.compare_exchange_weak( st, newst, std::memory_order_relaxed, std::memory_order_relaxed );
|
state_.compare_exchange_weak( st, newst, std::memory_order_relaxed, std::memory_order_relaxed );
|
||||||
}
|
}
|
||||||
|
|
||||||
boost::core::sp_thread_pause();
|
yield( k );
|
||||||
}
|
|
||||||
|
|
||||||
// clear writer pending bit before going to sleep
|
|
||||||
|
|
||||||
{
|
|
||||||
std::uint32_t st = state_.load( std::memory_order_relaxed );
|
|
||||||
|
|
||||||
for( ;; )
|
|
||||||
{
|
|
||||||
if( st & locked_exclusive_mask )
|
|
||||||
{
|
|
||||||
// locked exclusive, nothing to do
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
else if( ( st & reader_lock_count_mask ) == 0 )
|
|
||||||
{
|
|
||||||
// lock free, try to take it
|
|
||||||
|
|
||||||
std::uint32_t newst = locked_exclusive_mask;
|
|
||||||
if( state_.compare_exchange_weak( st, newst, std::memory_order_acquire, std::memory_order_relaxed ) ) return;
|
|
||||||
}
|
|
||||||
else if( ( st & writer_pending_mask ) == 0 )
|
|
||||||
{
|
|
||||||
// writer pending bit already clear, nothing to do
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// clear writer pending bit
|
|
||||||
|
|
||||||
std::uint32_t newst = st & ~writer_pending_mask;
|
|
||||||
if( state_.compare_exchange_weak( st, newst, std::memory_order_relaxed, std::memory_order_relaxed ) ) break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
boost::core::sp_thread_sleep();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user