一、介紹
在WonderTrader的文件SpinMutex.hpp定義了跨平臺的自旋鎖的實現。
二、實現原理
1、類 SpinMutex:自旋鎖實現
SpinMutex 是一個輕量級的自旋鎖(Spinlock)實現,用于多線程之間保護臨界區資源。自旋鎖通過不斷嘗試獲取鎖而不讓出 CPU 控制權,在臨界區非常短的場景下比 std::mutex 更高效
類定義與成員變量
class SpinMutex
{
private:std::atomic<bool> flag = { false };
含義:
- flag 是一個原子布爾變量,標志鎖的狀態:
- false:鎖未被占用。
- true:鎖已被占用。
- 使用 std::atomic 保證該變量在線程之間的讀寫是原子的,不會產生數據競爭。
lock() 方法:嘗試加鎖(進入臨界區)
void lock()
{for (;;){if (!flag.exchange(true, std::memory_order_acquire))break;while (flag.load(std::memory_order_relaxed)){
#ifdef _MSC_VER_mm_pause();
#else__builtin_ia32_pause();
#endif}}
}
(1)、嘗試搶鎖
if (!flag.exchange(true, std::memory_order_acquire))break;
含義:
- 嘗試將 flag 從 false 變成 true。
- exchange 是一個原子操作,返回交換前的值。
- 如果原值是 false,說明鎖空閑,搶鎖成功,跳出循環。
- memory_order_acquire 的作用:
- 表示獲取操作:確保當前線程在獲取鎖之后,看到的所有共享內存變動是“可見的”。
- 保證鎖之后的內存操作不會重排到 exchange 之前。
(2)、鎖被占用,進入自旋等待
while (flag.load(std::memory_order_relaxed))
{
#ifdef _MSC_VER_mm_pause();
#else__builtin_ia32_pause();
#endif
}
含義:
- 如果搶鎖失敗,說明 flag == true,就會進入這個 while,不斷檢測鎖是否釋放。
- 自旋期間只讀取,不嘗試修改。
- memory_order_relaxed:
- 只要求原子性,不需要內存可見性或順序一致性。
- 適合用于自旋中不斷讀狀態,無需同步其他內存操作。
- _mm_pause() / __builtin_ia32_pause():
- 都是CPU pause 指令,告訴處理器“我在忙等,不要發熱也 不要讓亂序執行干擾這個循環”。
- 優化超線程(HT)下的性能,降低能耗和緩存一致性壓力。
- _mm_pause() 是 Intel/微軟的,__builtin_ia32_pause() 是 GCC/Clang 提供的
這段代碼的整體思路:
1 嘗試交換(CAS):把 flag 從 false 設置為 true。
2 成功 → 搶到鎖,退出。
3 失敗 → 等著別人釋放(即 flag 變為 false)。
4 不斷讀(load)+ pause,直到別人釋放鎖,繼續嘗試搶鎖。
unlock() 方法:釋放鎖
void unlock()
{flag.store(false, std::memory_order_release);
}
含義:
- 將 flag 設為 false,表示鎖釋放,別人可以搶鎖了。
- memory_order_release:
- 表示釋放操作:保證當前線程在釋放鎖前對共享內存的所有寫操作,對下一個加鎖的線程是可見的。
- 保證寫操作不會重排序到 store 之后。
整體流程
Thread A Thread B
--------- ----------
flag == false
↓
exchange(true) → 成功
flag = true(鎖住)
執行臨界區
↓
store(false)(解鎖) load(flag) → falseexchange(true) → 成功進入臨界區
2、類 SpinLock:RAII 自旋鎖管理器
構造函數:
SpinLock(SpinMutex& mtx) :_mutex(mtx) { _mutex.lock(); }
接收一個 SpinMutex 引用,并立即加鎖。
析構函數:
~SpinLock() { _mutex.unlock(); }
離開作用域時自動釋放鎖,避免忘記 unlock() 導致死鎖。
拷貝構造 & 賦值刪除:
SpinLock(const SpinLock&) = delete;
SpinLock& operator=(const SpinLock&) = delete;
禁止復制和賦值,避免一個鎖對象被多次釋放,保證線程安全。
三、使用舉例
#include "SpinMutex.hpp"
#include <vector>
#include <thread>SpinMutex spin_mtx;
int counter = 0;
void worker(int id, int loops)
{for (int i = 0; i < loops; ++i){SpinLock lock(spin_mtx); // 自動加鎖++counter; // 臨界區// 離開作用域時自動解鎖}
}
int main() {int thread_count = 4;int loops = 100000;std::vector<std::thread> threads;threads.reserve(thread_count);for (int i = 0; i < thread_count; ++i)threads.emplace_back(worker, i, loops);for (auto& t : threads)t.join();std::cout << "Final counter = " << counter << std::endl;
}