Skip to content

Commit

Permalink
优化自旋锁相关代码.
Browse files Browse the repository at this point in the history
  • Loading branch information
hxrain committed Feb 2, 2021
1 parent 4987283 commit a0524a7
Show file tree
Hide file tree
Showing 4 changed files with 44 additions and 29 deletions.
14 changes: 12 additions & 2 deletions rx_lock_base.h
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,14 @@
#include "rx_assert.h"
#include "rx_cc_atomic.h"


//PAUSE指令提升了自旋等待循环的性能,处理器利用这个提示可以避免在大多数情况下的内存顺序违规
#if (RX_CC==RX_CC_CLANG)||(RX_CC==RX_CC_GCC)
#define rx_mm_pause() __asm__ __volatile__ ("pause\n")
#else
#define rx_mm_pause() _mm_pause()
#endif

namespace rx
{
//------------------------------------------------------
Expand Down Expand Up @@ -57,7 +65,7 @@ namespace rx
{
//尝试设置标记为真,如果返回旧值为假,则意味着抢到了锁.否则死循环.
mem_barrier();
while (!rx_atomic_cas(m_lock, 0, 1));
while (!rx_atomic_cas(m_lock, 0, 1)) rx_mm_pause();
return true;
}
//--------------------------------------------------
Expand All @@ -73,8 +81,10 @@ namespace rx
bool trylock(bool is_wr_lock = true)
{
uint32_t lc = 0;
while (lc < m_max_retry && !rx_atomic_cas(m_lock, 0, 1))
while (lc < m_max_retry && !rx_atomic_cas(m_lock, 0, 1)) {
rx_mm_pause();
++lc;
}
return lc < m_max_retry;
}
};
Expand Down
9 changes: 1 addition & 8 deletions rx_lock_os.h
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
#include "rx_lock_base.h"


//#define rx_mm_pause() //cpu级休眠指令

#define rx_sleep rx_thread_yield //sleep(毫秒)
inline void rx_thread_yield(uint32_t ms); //让线程休眠指定的时间(毫秒)
inline bool rx_thread_yield(); //让当前线程让步给本核上的其他线程,返回值告知是否切换成功
Expand Down Expand Up @@ -38,8 +38,6 @@ class rw_locker_t; //进程内不可递归读写锁
//让当前线程让步给本核上的其他线程,返回值告知是否切换成功
inline bool rx_thread_yield() { return !sched_yield(); }

#define rx_mm_pause() __asm__ __volatile__ ("pause\n")

#elif RX_IS_OS_WIN

#include <process.h>
Expand All @@ -53,11 +51,6 @@ class rw_locker_t; //进程内不可递归读写锁
//让当前线程让步给本核上的其他线程,返回值告知是否切换成功
inline bool rx_thread_yield() {return !!SwitchToThread();}

#if (RX_CC==RX_CC_CLANG)||(RX_CC==RX_CC_GCC)
#define rx_mm_pause() __asm__ __volatile__ ("pause\n")
#else
#define rx_mm_pause() _mm_pause()
#endif
#endif


Expand Down
48 changes: 30 additions & 18 deletions rx_lock_spin.h
Original file line number Diff line number Diff line change
Expand Up @@ -11,18 +11,19 @@
#endif

#if !defined(RX_SPIN_ROUND_THRESHOLD)
#define RX_SPIN_ROUND_THRESHOLD 8 // 自旋轮数阀值,进行休眠策略的调整
#define RX_SPIN_ROUND_THRESHOLD 10 // 自旋轮数阀值,进行休眠策略的调整
#endif

//---------------------------------------------------------
//自旋锁高级休眠策略:rounds记录第几轮休眠;pauses记录低轮数模式中的空转次数(建议使用2的n次方);THRESHOLD告知高低轮数切换临界点.
inline void rx_spin_loop_pause(uint32_t &rounds, uint32_t &pauses, const uint32_t THRESHOLD = RX_SPIN_ROUND_THRESHOLD)
inline void rx_spin(uint32_t &rounds, uint32_t &pauses, const uint32_t THRESHOLD = RX_SPIN_ROUND_THRESHOLD)
{
rx_assert(THRESHOLD <= 32);
if (rounds < THRESHOLD)
{
//先进行CPU级的短休眠尝试
for (int32_t i = pauses; i > 0; --i)
rx_mm_pause(); // 这是为支持超线程的 CPU 准备的切换提示
rx_mm_pause(); // 自旋提示
pauses = pauses << 1; // 短自旋次数指数翻倍
}
else
Expand All @@ -41,6 +42,20 @@ inline void rx_spin_loop_pause(uint32_t &rounds, uint32_t &pauses, const uint32_

namespace rx
{
//------------------------------------------------------
// 自旋锁多策略休眠功能
class spin_sleep_t
{
uint32_t m_rounds; //记录休眠轮数
uint32_t m_pauses; //记录快速休眠的空转次数
public:
spin_sleep_t() :m_rounds(0), m_pauses(1) {}
//进行休眠
void operator()(uint32_t threshold = RX_SPIN_ROUND_THRESHOLD) { rx_spin(m_rounds, m_pauses, threshold); }
//获取已休眠轮数
uint32_t rounds() { return m_rounds; }
};

//------------------------------------------------------
//参考: https://github.com/shines77/RingQueue/blob/master/include/RingQueue/RingQueue.h
//基于原子变量实现的自旋锁,不可递归
Expand All @@ -61,10 +76,9 @@ namespace rx
if (rx_atomic_swap(m_lock, 1) != 0) // 旧值为0时(空锁)则直接成功
{
// 原子锁定进行循环尝试,中间夹杂必要的调度休眠
uint32_t rounds = 0;
uint32_t pauses = 4;
spin_sleep_t spin;
do
rx_spin_loop_pause(rounds, pauses, RX_SPIN_ROUND_THRESHOLD);// 进行休眠
spin(); // 进行休眠
while (!trylock()); // 再次尝试原子锁定
}
return true;
Expand Down Expand Up @@ -103,13 +117,12 @@ namespace rx
mem_barrier(); // 编译器读写屏障
rx_atomic_add(m_lock, 1); // 计数增加

uint32_t rounds = 0;
uint32_t pauses = 4;
do {
rx_spin_loop_pause(rounds, pauses, RX_SPIN_ROUND_THRESHOLD);// 进行休眠
if (timeout_rounds && rounds > timeout_rounds)
spin_sleep_t spin;
while (!rx_atomic_load(m_lock)) { // 判断发令枪是否触发
spin(); // 进行休眠
if (timeout_rounds && spin.rounds() > timeout_rounds)
return false; // 轮数超时
} while (!rx_atomic_load(m_lock)); // 判断发令枪是否触发
}

return true;
}
Expand All @@ -119,13 +132,12 @@ namespace rx
{
mem_barrier(); // 编译器读写屏障

uint32_t rounds = 0;
uint32_t pauses = 4;
do {
rx_spin_loop_pause(rounds, pauses, RX_SPIN_ROUND_THRESHOLD);// 进行休眠
if (timeout_rounds && rounds > timeout_rounds)
spin_sleep_t spin;
while (rx_atomic_load(m_lock) != expected) { // 等待人员都到齐
spin(); // 进行休眠
if (timeout_rounds && spin.rounds() > timeout_rounds)
return false; // 轮数超时
} while (rx_atomic_load(m_lock) != expected); // 等待人员都到齐
}

rx_atomic_store(m_lock, 0); // 发令枪响了
return true;
Expand Down
2 changes: 1 addition & 1 deletion test/base/vs_2015.sln
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio 14
VisualStudioVersion = 14.0.25420.1
MinimumVisualStudioVersion = 10.0.40219.1
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ut_base", "vs_2015.vcxproj", "{7411625F-1616-4241-89C0-85033CA4675C}"
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "vs_2015", "vs_2015.vcxproj", "{7411625F-1616-4241-89C0-85033CA4675C}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Expand Down

0 comments on commit a0524a7

Please sign in to comment.