最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

C++自旋鎖的實(shí)現(xiàn)示例

 更新時(shí)間:2026年02月13日 11:37:30   作者:碼上睡覺(jué)  
自旋鎖是一種非阻塞鎖,線(xiàn)程在獲取鎖失敗時(shí)會(huì)忙等待而不是掛起,它適用于鎖持有時(shí)間極短的場(chǎng)景,可以在用戶(hù)態(tài)運(yùn)行,避免系統(tǒng)調(diào)用開(kāi)銷(xiāo),下面就來(lái)詳細(xì)的介紹一下C++自旋鎖的使用,感興趣的可以了解一下

一、 什么是自旋鎖?

核心定義:

自旋鎖是一種非阻塞鎖。當(dāng)線(xiàn)程嘗試獲取鎖失敗時(shí),它不會(huì)掛起(阻塞/讓出 CPU),而是會(huì)在一個(gè)死循環(huán)中持續(xù)檢查(忙等待 / Busy-Waiting)鎖是否被釋放。

直觀隱喻

互斥鎖 (Mutex):你去洗手間,發(fā)現(xiàn)門(mén)鎖了。你回到座位上睡覺(jué)。等里面的人出來(lái)了,管理員把你叫醒,你再去上。

  • 開(kāi)銷(xiāo):睡覺(jué)(切換上下文)和被叫醒(調(diào)度)很累。

自旋鎖 (Spinlock):你去洗手間,發(fā)現(xiàn)門(mén)鎖了。你站在門(mén)口,每隔 0.1 秒就敲門(mén)問(wèn):“好了沒(méi)?好了沒(méi)?”,直到里面的人出來(lái)。

  • 開(kāi)銷(xiāo):你一直站著(占用 CPU),哪里也去不了。但是一旦門(mén)開(kāi)了,你零延遲沖進(jìn)去。

二、 為什么需要自旋鎖?(底層視角)

您可能會(huì)問(wèn):“讓線(xiàn)程空轉(zhuǎn)浪費(fèi) CPU,這不是很傻嗎?”

要理解它的價(jià)值,必須看**上下文切換(Context Switch)**的成本。

  1. Mutex 的成本
  • 當(dāng) std::mutex 拿不到鎖時(shí),線(xiàn)程會(huì)陷入內(nèi)核態(tài)(Kernel Mode)。
  • OS 需要保存當(dāng)前線(xiàn)程的寄存器、棧指針,刷新 TLB(頁(yè)表緩存),然后調(diào)度另一個(gè)線(xiàn)程。
  • 這個(gè)過(guò)程大約需要 3 ~ 10 微秒(在現(xiàn)代 CPU 上)。
  1. Spinlock 的優(yōu)勢(shì)
  • 如果您的臨界區(qū)代碼執(zhí)行時(shí)間極短(比如只是做一個(gè) pNext = node; 的鏈表操作),耗時(shí)可能只有 0.01 微秒。
  • 為了等待 0.01 微秒的任務(wù),去花費(fèi) 5 微秒切換線(xiàn)程,是虧本生意。
  • 自旋鎖全程在**用戶(hù)態(tài)(User Mode)**運(yùn)行,完全沒(méi)有系統(tǒng)調(diào)用開(kāi)銷(xiāo)。

結(jié)論:自旋鎖適用于**“鎖持有時(shí)間極短”**的場(chǎng)景。

三、 C++ 中的自旋鎖實(shí)現(xiàn)

C++ 標(biāo)準(zhǔn)庫(kù)并沒(méi)有直接提供 std::spinlock(C++20 只有 std::atomic_flag),我們需要利用原子操作自己實(shí)現(xiàn)。

1. 最基礎(chǔ)的實(shí)現(xiàn):std::atomic_flag

這是 C++ 中唯一保證**無(wú)鎖(Lock-Free)**的數(shù)據(jù)類(lèi)型。

#include <atomic>
#include <thread>
#include <vector>
#include <iostream>
 
class SpinLock {
private:
// atomic_flag 只有兩個(gè)狀態(tài):set (true) 和 clear (false)
// ATOMIC_FLAG_INIT 初始化為 false
std::atomic_flag flag = ATOMIC_FLAG_INIT;
 
public:
void lock() {
    // test_and_set(): 
    // 1. 讀取當(dāng)前值
    // 2. 將值設(shè)為 true
    // 3. 返回舊值
    // 這是一個(gè)原子操作 (RMW: Read-Modify-Write)
 
    // 如果返回 true,說(shuō)明之前已經(jīng)是 true (被別人鎖了),則一直循環(huán) (自旋)
    // memory_order_acquire: 保證獲得鎖之后的讀寫(xiě)操作不會(huì)重排到加鎖之前
    while (flag.test_and_set(std::memory_order_acquire)) {
        // 這里是自旋區(qū) (Spinning)
        // 可以在這里加 "CPU pause" 指令優(yōu)化(后面會(huì)講)
    }
}
 
void unlock() {
    // 清除標(biāo)志,設(shè)為 false
    // memory_order_release: 保證解鎖之前的讀寫(xiě)操作全部完成
    flag.clear(std::memory_order_release);
}
};
 
// 使用示例(配合 lock_guard 滿(mǎn)足 RAII)
SpinLock sl;
void worker() {
    // std::lock_guard 需要類(lèi)滿(mǎn)足 BasicLockable (有 lock/unlock 方法)
    std::lock_guard<SpinLock> guard(sl); 
    // 臨界區(qū)...
}

2. 通用實(shí)現(xiàn):std::atomic<bool>

功能類(lèi)似,但 atomic<bool> 可以提供更多 API(比如 load 查看狀態(tài)),只是在極老的硬件上可能不是 Lock-Free 的(雖然現(xiàn)在幾乎都是)。

class SpinLockBool {
std::atomic<bool> locked{false};
public:
void lock() {
    bool expected = false;
    // CAS (Compare And Swap)
    // 嘗試把 locked 從 false 改成 true
    // 如果 locked 是 true (被鎖),compare_exchange_weak 返回 false,繼續(xù)循環(huán)
    while (!locked.compare_exchange_weak(expected, true, std::memory_order_acquire)) {
        expected = false; // CAS 失敗后 expected 會(huì)被改成當(dāng)前值(true),重置為 false 再次嘗試
    }
}
void unlock() {
    locked.store(false, std::memory_order_release);
}
};

四、 致命陷阱與性能優(yōu)化(C++ 高階)

在實(shí)現(xiàn)高性能組件(如內(nèi)存池)時(shí),直接用 while(flag.test_and_set()) 會(huì)帶來(lái)嚴(yán)重的性能問(wèn)題。

1. 緩存一致性風(fēng)暴 (Cache Coherence Storm / Bus Contention)

現(xiàn)象:多個(gè)線(xiàn)程在一個(gè)原子變量上瘋狂 CAS(寫(xiě)操作)。

原理:根據(jù) CPU 的 MESI 協(xié)議,當(dāng)一個(gè)核修改原子變量時(shí),必須讓其他核的 Cache Line 失效。如果 10 個(gè)線(xiàn)程同時(shí)自旋,鎖變量所在的 Cache Line 會(huì)在 CPU 核心之間瘋狂“跳來(lái)跳去”,導(dǎo)致總線(xiàn)流量爆炸,甚至拖慢其他不相關(guān)線(xiàn)程的速度。

解決Test-Test-and-Set (TTAS) 模式。

  • 先用 load (讀) 檢查是否被釋放(讀操作不獨(dú)占 Cache Line)。
  • 只有讀到 false 時(shí),才嘗試 CAS (寫(xiě))。

2. CPU 流水線(xiàn)空轉(zhuǎn)

現(xiàn)象while 循環(huán)是一個(gè)極緊密的指令序列,CPU 流水線(xiàn)會(huì)全速運(yùn)行,產(chǎn)生大量熱量并消耗電力。

解決:CPU Pause 指令。

在 x86 架構(gòu)下,使用 _mm_pause() 指令(SSE2 擴(kuò)展)。

  1. 它告訴 CPU “我在自旋”,讓 CPU 稍微降低流水線(xiàn)派發(fā)速度,節(jié)能降溫。
  2. 它可以避免退出循環(huán)時(shí)的內(nèi)存順序沖突懲罰。

優(yōu)化后的 C++ 代碼:

#include <atomic>
#include <immintrin.h> // for _mm_pause
 
class OptimizedSpinLock {
std::atomic_flag flag = ATOMIC_FLAG_INIT;
public:
void lock() {
    while (flag.test_and_set(std::memory_order_acquire)) {
        // 在自旋期間...
        while (flag.test(std::memory_order_relaxed)) { // 先只讀 (Test)
            // 告訴 CPU 稍微休息一下,不要全速空轉(zhuǎn)
            #if defined(__x86_64__) || defined(_M_X64)
            _mm_pause(); 
            #endif
            // 如果是 ARM 架構(gòu),可以用 __yield() 或 asm("yield")
        }
    }
}
void unlock() {
    flag.clear(std::memory_order_release);
}
};

3. 優(yōu)先級(jí)反轉(zhuǎn)與死鎖

  • 場(chǎng)景:如果一個(gè)低優(yōu)先級(jí)線(xiàn)程拿到了自旋鎖,但因?yàn)楸?OS 調(diào)度走了(時(shí)間片到了),一個(gè)高優(yōu)先級(jí)線(xiàn)程被調(diào)度進(jìn)來(lái),嘗試獲取同一個(gè)自旋鎖。
  • 結(jié)果:高優(yōu)先級(jí)線(xiàn)程因?yàn)槭亲孕Φ龋?,它不讓?CPU,導(dǎo)致低優(yōu)先級(jí)線(xiàn)程永遠(yuǎn)得不到 CPU 來(lái)執(zhí)行解鎖操作。于是死鎖。
  • 對(duì)策:在自旋鎖中,如果自旋超過(guò)一定次數(shù),必須使用 std::this_thread::yield() 主動(dòng)讓出時(shí)間片。

到此這篇關(guān)于C++自旋鎖的實(shí)現(xiàn)示例的文章就介紹到這了,更多相關(guān)C++自旋鎖內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

最新評(píng)論

嘉义市| 崇礼县| 微山县| 仪陇县| 三亚市| 独山县| 瑞丽市| 大港区| 佛坪县| 花莲县| 资中县| 博白县| 嵊泗县| 齐齐哈尔市| 石嘴山市| 股票| 治多县| 河源市| 建宁县| 司法| 康乐县| 商城县| 乾安县| 宁强县| 濮阳县| 隆化县| 桃江县| 房山区| 余干县| 应用必备| 松潘县| 定襄县| 兴安县| 林西县| 垦利县| 盱眙县| 宜川县| 新密市| 黄平县| 扬中市| 苍山县|