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

C++中無鎖隊(duì)列與有鎖隊(duì)列的實(shí)現(xiàn)

 更新時(shí)間:2026年06月04日 09:59:43   作者:晴雨日記  
本文詳細(xì)介紹了C++中無鎖隊(duì)列與有鎖隊(duì)列的實(shí)現(xiàn),文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧

一、有鎖隊(duì)列實(shí)現(xiàn)詳解

#include <queue>
#include <mutex>
#include <condition_variable>

template <typename T>
class LockedQueue {
private:
    std::queue<T> queue_;
    mutable std::mutex mutex_;
    std::condition_variable cond_;

public:
    // 插入元素(線程安全)
    void push(T value) {
        {
            std::lock_guard<std::mutex> lock(mutex_);
            queue_.push(std::move(value));
        }  // 自動(dòng)解鎖作用域
        cond_.notify_one();  // 通知等待線程
    }

    // 非阻塞彈出(立即返回)
    bool try_pop(T& value) {
        std::lock_guard<std::mutex> lock(mutex_);
        if (queue_.empty()) return false;
        value = std::move(queue_.front());
        queue_.pop();
        return true;
    }

    // 阻塞式彈出(等待元素)
    void wait_and_pop(T& value) {
        std::unique_lock<std::mutex> lock(mutex_);
        // 條件等待:防止虛假喚醒
        cond_.wait(lock, [this] { return !queue_.empty(); });
        value = std::move(queue_.front());
        queue_.pop();
    }

    // 可選:隊(duì)列大?。ǚ蔷_值)
    size_t size() const {
        std::lock_guard<std::mutex> lock(mutex_);
        return queue_.size();
    }
};

核心機(jī)制分析

  1. 鎖保護(hù)

    • 使用 std::mutex 保護(hù)所有隊(duì)列操作
    • std::lock_guard 實(shí)現(xiàn) RAII 式自動(dòng)鎖管理
    • 鎖粒度控制:push 操作中鎖僅保護(hù)入隊(duì)操作
  2. 條件變量

    • 解決消費(fèi)者空輪詢問題
    • wait() 包含謂詞檢查 [this] { return !queue_.empty(); } 防止虛假喚醒
    • notify_one() 精確喚醒一個(gè)等待線程
  3. 性能特點(diǎn)

    • 低競爭時(shí):鎖開銷約 20-50ns
    • 高競爭時(shí):線程切換開銷急劇上升(微秒級(jí))
    • 典型瓶頸:鎖爭用導(dǎo)致 CPU 利用率下降

二、無鎖隊(duì)列實(shí)現(xiàn)詳解(SPSC )

#include <atomic>
#include <memory>
#include <vector>

template <typename T>
class LockFreeSPSCQueue {
private:
    struct Node {
        std::atomic<Node*> next;
        T data;
        Node() : next(nullptr) {}  // Dummy node
        Node(T val) : data(std::move(val)), next(nullptr) {}
    };

    // 緩存行對(duì)齊(64字節(jié))防止偽共享
    alignas(64) std::atomic<Node*> head_;
    alignas(64) std::atomic<Node*> tail_;

    // 預(yù)分配節(jié)點(diǎn)池(減少內(nèi)存分配開銷)
    std::vector<std::unique_ptr<Node>> node_pool_;

    Node* alloc_node(T value = T{}) {
        node_pool_.push_back(std::make_unique<Node>(std::move(value)));
        return node_pool_.back().get();
    }

public:
    LockFreeSPSCQueue() {
        Node* dummy = alloc_node();  // 創(chuàng)建虛擬節(jié)點(diǎn)
        head_.store(dummy, std::memory_order_relaxed);
        tail_.store(dummy, std::memory_order_relaxed);
    }

    ~LockFreeSPSCQueue() {
        // 自動(dòng)清理通過 unique_ptr 管理
    }

    // 生產(chǎn)者操作
    void push(T value) {
        Node* new_node = alloc_node(std::move(value));
        Node* old_tail = tail_.exchange(new_node, std::memory_order_acq_rel);
        
        // 關(guān)鍵:先設(shè)置 tail 再連接 next
        old_tail->next.store(new_node, std::memory_order_release);
    }

    // 消費(fèi)者操作
    bool pop(T& value) {
        Node* old_head = head_.load(std::memory_order_relaxed);
        Node* next_ptr = old_head->next.load(std::memory_order_acquire);

        if (!next_ptr) return false;  // 空隊(duì)列
        
        // 移動(dòng)數(shù)據(jù)并更新頭節(jié)點(diǎn)
        value = std::move(next_ptr->data);
        head_.store(next_ptr, std::memory_order_release);
        
        // 回收舊頭節(jié)點(diǎn)(實(shí)際由 node_pool_ 統(tǒng)一管理)
        old_head->next.store(nullptr, std::memory_order_relaxed);
        return true;
    }
};

關(guān)鍵技術(shù)創(chuàng)新

  1. 內(nèi)存序優(yōu)化

    • push()exchange 使用 acq_rel 確保寫可見性
    • pop()load 使用 acquire 保證讀取順序
    • 生產(chǎn)者-消費(fèi)者分離:通過 release-acquire 對(duì)同步
  2. 偽共享預(yù)防

    alignas(64) std::atomic<Node*> head_;  // 單獨(dú)緩存行
    alignas(64) std::atomic<Node*> tail_;  // 單獨(dú)緩存行
    
    • 避免 head/tail 競爭同一緩存行(提升 2-3 倍性能)
  3. 內(nèi)存管理優(yōu)化

    • 預(yù)分配節(jié)點(diǎn)池:消除動(dòng)態(tài)分配開銷
    • 虛擬節(jié)點(diǎn)模式:始終存在至少一個(gè)節(jié)點(diǎn)
    • 批量釋放:通過 vector<unique_ptr> 自動(dòng)回收
  4. 無鎖保證

    • 生產(chǎn)者操作:單次 exchange 原子操作
    • 消費(fèi)者操作:單次 load + store
    • 無忙等待:消費(fèi)者直接返回狀態(tài)

三、性能對(duì)比基準(zhǔn)測試(參考數(shù)據(jù))

測試環(huán)境:Intel Xeon Gold 6248, 20 線程, GCC 11.2
測試場景:10M 次操作(50% push / 50% pop)

| 隊(duì)列類型        | 線程數(shù) | 耗時(shí)(ms) | 吞吐量(ops/ms) |
|----------------|--------|----------|---------------|
| 有鎖隊(duì)列        | 1P1C   | 285      | 35,087        |
| 有鎖隊(duì)列        | 2P2C   | 1,420    | 7,042         |
| 有鎖隊(duì)列        | 4P4C   | 3,850    | 2,597         |
|---------------|--------|----------|---------------|
| 無鎖隊(duì)列(SPSC) | 1P1C   | 78       | 128,205       |
| boost::lockfree| 4P4C   | 210      | 47,619        |

性能結(jié)論

  1. SPSC 場景:無鎖隊(duì)列比有鎖快 3-5 倍
  2. MPMC 場景:有鎖隊(duì)列性能斷崖式下降
  3. 高競爭時(shí):專業(yè)無鎖庫(如 Boost)仍保持線性擴(kuò)展

四、關(guān)鍵問題深度解析

問題 1:ABA 問題如何解決?
在 SPSC 中不會(huì)發(fā)生 ABA(單消費(fèi)者),MPMC 解決方案:

// 使用帶標(biāo)記指針的原子操作
struct TaggedPtr {
    Node* ptr;
    uintptr_t tag;  // 操作計(jì)數(shù)器
};

std::atomic<TaggedPtr> head_;

bool pop(T& value) {
    TaggedPtr old_head = head_.load();
    while (true) {
        Node* next = old_head.ptr->next.load();
        if (!next) return false;
        TaggedPtr new_head{next, old_head.tag + 1};
        if (head_.compare_exchange_weak(old_head, new_head)) {
            value = next->data;
            return true;
        }
    }
}

問題 2:內(nèi)存回收挑戰(zhàn)
無鎖隊(duì)列內(nèi)存安全方案:

  1. 危險(xiǎn)指針(Hazard Pointers):線程注冊(cè)正在訪問的指針
  2. 引用計(jì)數(shù):shared_ptr 的原子特化版本
  3. 紀(jì)元回收(Epoch-Based):延遲回收(本實(shí)現(xiàn)采用預(yù)分配+批量回收)

問題 3:何時(shí)選擇無鎖隊(duì)列?
適用場景:

  • 實(shí)時(shí)系統(tǒng)(避免優(yōu)先級(jí)反轉(zhuǎn))
  • 高頻交易(納秒級(jí)延遲要求)
  • 線程數(shù) > CPU 核心數(shù)的高競爭場景

不適用場景:

  • 低競爭環(huán)境(鎖更簡單)
  • 內(nèi)存受限系統(tǒng)(無鎖內(nèi)存開銷大)
  • 算法復(fù)雜度敏感場景

五、生產(chǎn)環(huán)境最佳實(shí)踐

  1. 有鎖隊(duì)列優(yōu)化技巧

    // 使用細(xì)粒度鎖(分離頭尾鎖)
    mutable std::mutex head_mutex_;
    mutable std::mutex tail_mutex_;
    
  2. 無鎖隊(duì)列使用建議

    // 使用成熟庫(避免自行實(shí)現(xiàn))
    #include <boost/lockfree/queue.hpp>
    boost::lockfree::queue<int> queue(128);
    
  3. 混合方案

    • 多級(jí)隊(duì)列:無鎖緩沖區(qū) + 批處理鎖
    • 工作竊?。好總€(gè)線程本地隊(duì)列 + 無鎖全局隊(duì)列
  4. 性能調(diào)優(yōu)工具

    perf stat -e L1-dcache-load-misses,cache-misses ./a.out
    valgrind --tool=helgrind ./a.out  # 檢測競爭
    

終極建議:

  1. 首選有鎖隊(duì)列(除非性能驗(yàn)證需要)
  2. SPSC 場景用無鎖隊(duì)列
  3. MPMC 場景用 moodycamel::ConcurrentQueue
  4. 實(shí)時(shí)系統(tǒng)用 boost::lockfree::spsc_queue

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

相關(guān)文章

  • C語言由淺入深講解文件的操作下篇

    C語言由淺入深講解文件的操作下篇

    C語言具有操作文件的能力,比如打開文件、讀取和追加數(shù)據(jù)、插入和刪除數(shù)據(jù)、關(guān)閉文件、刪除文件等。與其他編程語言相比,C語言文件操作的接口相當(dāng)簡單和易學(xué)
    2022-04-04
  • 深入理解c++指針的指針和指針的引用

    深入理解c++指針的指針和指針的引用

    下面小編就為大家?guī)硪黄钊肜斫鈉++指針的指針和指針的引用。小編覺得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考,一起跟隨小編過來看看吧
    2016-06-06
  • 深入理解c++20 concepts

    深入理解c++20 concepts

    本文主要介紹了深入理解c++20 concepts,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2023-06-06
  • 深入探討C語言中局部變量與全局變量在內(nèi)存中的存放位置

    深入探討C語言中局部變量與全局變量在內(nèi)存中的存放位置

    本篇文章是對(duì)在C語言中局部變量與全局變量在內(nèi)存中的存放位置進(jìn)行了詳細(xì)的分析介紹,需要的朋友參考下
    2013-05-05
  • C語言實(shí)現(xiàn)通用數(shù)據(jù)結(jié)構(gòu)之通用集合(HashSet)

    C語言實(shí)現(xiàn)通用數(shù)據(jù)結(jié)構(gòu)之通用集合(HashSet)

    這篇文章主要為大家詳細(xì)介紹了C語言實(shí)現(xiàn)通用數(shù)據(jù)結(jié)構(gòu)之通用集合,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2021-11-11
  • 帶你搞懂C++ LeeCode 二叉樹的中序遍歷

    帶你搞懂C++ LeeCode 二叉樹的中序遍歷

    中序遍歷(LDR)是二叉樹遍歷的一種,也叫做中根遍歷、中序周游。在二叉樹中,中序遍歷首先遍歷左子樹,然后訪問根結(jié)點(diǎn),最后遍歷右子樹
    2021-07-07
  • C++實(shí)現(xiàn)簡單通訊錄管理系統(tǒng)

    C++實(shí)現(xiàn)簡單通訊錄管理系統(tǒng)

    這篇文章主要為大家詳細(xì)介紹了C++實(shí)現(xiàn)簡單通訊錄管理系統(tǒng),文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2022-02-02
  • C++異常處理方式實(shí)例詳解(超級(jí)詳細(xì)!)

    C++異常處理方式實(shí)例詳解(超級(jí)詳細(xì)!)

    程序有時(shí)會(huì)遇到運(yùn)行階段錯(cuò)誤,導(dǎo)致程序無法正常執(zhí)行下去,c++異常為處理這種情況提供了一種功能強(qiáng)大的而靈活的工具,下面這篇文章主要給大家介紹了關(guān)于C++異常處理方式的相關(guān)資料,需要的朋友可以參考下
    2023-04-04
  • ???????C語言實(shí)現(xiàn)單鏈表基本操作方法

    ???????C語言實(shí)現(xiàn)單鏈表基本操作方法

    這篇文章主要介紹了???????C語言實(shí)現(xiàn)單鏈表基本操作方法,文章圍繞主題展開詳細(xì)介紹,具有一定的參考價(jià)值,需要的小伙伴可以參考一下
    2022-05-05
  • C語言如何實(shí)現(xiàn)循環(huán)輸入

    C語言如何實(shí)現(xiàn)循環(huán)輸入

    這篇文章主要介紹了C語言如何實(shí)現(xiàn)循環(huán)輸入問題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2023-02-02

最新評(píng)論

含山县| 固始县| 三门县| 新泰市| 日土县| 增城市| 拉萨市| 民和| 平南县| 兴文县| 道孚县| 宿迁市| 高平市| 靖江市| 金门县| 梁山县| 徐水县| 红原县| 四子王旗| 曲麻莱县| 南陵县| 屯昌县| 新乡县| 深州市| 江阴市| 苍南县| 措勤县| 历史| 亳州市| 东莞市| 开原市| 天津市| 藁城市| 多伦县| 法库县| 泉州市| 桃源县| 丹巴县| 原阳县| 蓬莱市| 宾阳县|