C++中TAS和CAS實現(xiàn)自旋鎖的示例
1.TAS和CAS介紹
它們是CPU 硬件提供的兩種最基礎的原子讀 - 改 - 寫(RMW)指令,專門用來解決多線程并發(fā)競爭問題,是所有鎖、無鎖結構的底層基石。
TAS = Test-And-Set 「測試并設置」
- 讀取內存里的舊值
- 強制把這個內存寫成 1(true)
- 返回剛才讀到的舊值
核心特征:一定會寫,不管原來是什么
CAS = Compare-And-Swap 「比較并交換」
- 拿內存當前值 和 你給的期望值對比
- 如果相等,才把內存改成新值
- 如果不等,什么都不做
- 返回是否修改成功
核心特征:條件寫入,不滿足就不碰內存
總結:
- TAS:先寫為占用,再告訴你之前是不是空閑
- CAS:先看是不是空閑,是才占用,不是就放棄
兩者都是原子操作,CPU 保證整個過程一步完成,不會被其他線程打斷。
2.TAS 使用場景:極簡自旋鎖
TAS 是 CPU 原生的最簡單原子指令,只能實現(xiàn)基礎互斥自旋鎖,優(yōu)點是代碼極簡,缺點是多核性能差。
#include <atomic>
#include <thread>
#include <iostream>
//intel指令
#include <immintrin.h>
//_mm_pause(); // 和 pause 匯編完全一樣
// 自旋等待優(yōu)化(x86)
#define asm_volatile_pause() asm volatile ("pause")
// --------------------------
// TAS 實現(xiàn):極簡自旋鎖
// 場景:臨界區(qū)極短、低并發(fā)、追求代碼最簡單
// --------------------------
class TasSpinLock {
private:
// C++ 原生 TAS 原子變量(硬件直接支持)
std::atomic_flag lock_ = ATOMIC_FLAG_INIT;
public:
void lock() {
// TAS 核心:test_and_set = 原子讀舊值 + 強制寫true
while (lock_.test_and_set(std::memory_order_acquire)) {
asm_volatile_pause(); // 自旋優(yōu)化
}
}
void unlock() {
lock_.clear(std::memory_order_release);
}
};
// 測試:多線程計數(shù)
int cnt = 0;
TasSpinLock tas_lock;
void work() {
for (int i = 0; i < 100000; ++i) {
std::lock_guard<TasSpinLock> guard(tas_lock);
cnt++;
}
}
int main() {
std::thread t1(work), t2(work);
t1.join(); t2.join();
std::cout << "TAS 自旋鎖結果: " << cnt << std::endl; // 200000
return 0;
}? 適合:簡單互斥、低并發(fā)、代碼極簡
? 不適合:多核高競爭(緩存顛簸嚴重)
3.CAS 核心使用場景
CAS 是現(xiàn)代并發(fā)編程的基石,支持條件寫入,自旋時不修改共享變量,多核性能遠超 TAS。
3.1.高性能自旋鎖(多核首選)
// --------------------------
// CAS 實現(xiàn):高性能自旋鎖
// 場景:多核高并發(fā)、低延遲臨界區(qū)
// --------------------------
class CasSpinLock {
private:
std::atomic<bool> locked_{false};
public:
void lock() {
bool expected = false;
// CAS 核心:只有值=expected(false),才寫入true
while (!locked_.compare_exchange_weak(
expected, true,
std::memory_order_acquire
)) {
expected = false; // 重置期望值
asm_volatile_pause();
}
}
void unlock() {
locked_.store(false, std::memory_order_release);
}
};3.2.無鎖線程安全計數(shù)器(不用鎖,純 CAS)
CAS 可以實現(xiàn)完全無鎖的并發(fā)操作,比自旋鎖更快:
// --------------------------
// CAS 實現(xiàn):無鎖原子計數(shù)器
// 場景:高并發(fā)計數(shù)(無鎖、高性能)
// --------------------------
std::atomic<int> cas_cnt{0};
void lock_free_count() {
int old_val, new_val;
for (int i = 0; i < 100000; ++i) {
do {
old_val = cas_cnt; // 讀舊值
new_val = old_val + 1;// 計算新值
// CAS:只有舊值沒被修改,才更新成功
} while (!cas_cnt.compare_exchange_weak(old_val, new_val));
}
}
// 測試
int main() {
std::thread t1(lock_free_count), t2(lock_free_count);
t1.join(); t2.join();
std::cout << "CAS 無鎖計數(shù)器: " << cas_cnt << std::endl; // 200000
return 0;
}3.3.線程安全變量更新(通用值替換)
// --------------------------
// CAS 實現(xiàn):安全更新共享變量
// 場景:任意線程安全值修改
// --------------------------
std::atomic<int> value{10};
void update_value(int target) {
int old = value;
// 只有當前值=old,才更新為target
if (value.compare_exchange_weak(old, target)) {
std::cout << "更新成功!\n";
} else {
std::cout << "值已被修改,更新失敗!\n";
}
}4.測試代碼
// ===================== C++ RAII 自動鎖(通用)=====================
template <typename Lock>
class ScopedLock {
private:
Lock& lock_;
public:
explicit ScopedLock(Lock& lock) : lock_(lock) { lock_.lock(); }
~ScopedLock() { lock_.unlock(); }
// 禁用拷貝
ScopedLock(const ScopedLock&) = delete;
ScopedLock& operator=(const ScopedLock&) = delete;
};
// ===================== 測試代碼 =====================
int counter = 0;
// 二選一測試:TasSpinLock 或 CasSpinLock
TasSpinLock spin_lock;
// CasSpinLock spin_lock;
// 線程工作函數(shù)
void work() {
for (int i = 0; i < 100000; ++i) {
ScopedLock<decltype(spin_lock)> lock(spin_lock); // 自動加鎖/解鎖
counter++;
}
}
int main() {
// 創(chuàng)建兩個線程競爭鎖
std::thread t1(work);
std::thread t2(work);
t1.join();
t2.join();
// 正確結果:200000
std::cout << "最終計數(shù): " << counter << std::endl;
return 0;
}5.TAS vs CAS對比
| 特性 | TAS 自旋鎖 | CAS 自旋鎖 |
|---|---|---|
| 原子操作 | atomic_exchange(強制寫) | atomic_cmpxchg(條件寫) |
| 自旋行為 | 每次循環(huán)都修改鎖變量 | 自旋時只讀,不修改 |
| 緩存性能 | 差(多核緩存顛簸、總線流量大) | 優(yōu)(緩存一致性友好) |
| 性能場景 | 單核 / 低競爭尚可,多核高競爭拉胯 | 多核 / 高競爭首選,現(xiàn)代標準實現(xiàn) |
| 靈活性 | 僅能做簡單自旋鎖 | 可實現(xiàn)無鎖隊列、公平鎖、futex 等 |
到此這篇關于C++中TAS和CAS實現(xiàn)自旋鎖的示例的文章就介紹到這了,更多相關C++ TAS和CAS自旋鎖內容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!

