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

淺析C++中的線程同步機制的實現(xiàn)那

 更新時間:2025年11月12日 08:54:23   作者:oioihoii  
本文主要介紹了C++中的線程同步機制淺析,文中通過示例代碼介紹的非常詳細,對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧

1. 為什么需要線程同步?

當(dāng)多個線程并發(fā)訪問共享數(shù)據(jù)(內(nèi)存、文件、網(wǎng)絡(luò)連接等)時,如果不進行任何同步控制,可能會引發(fā)一系列問題,最典型的是:

  • 數(shù)據(jù)競爭:一個線程在讀數(shù)據(jù)時,另一個線程在寫數(shù)據(jù),導(dǎo)致讀到的數(shù)據(jù)是“臟的”、不完整的或邏輯錯誤的。
  • 破壞不變量:對象在修改過程中,其內(nèi)部狀態(tài)可能暫時是不一致的(例如,修改一個鏈表時)。如果另一個線程在此時訪問該對象,會看到這個破碎的狀態(tài),導(dǎo)致未定義行為。

線程同步的核心目的是:通過強制特定代碼段的互斥訪問或執(zhí)行順序,來保證多線程環(huán)境下程序行為的正確性和可預(yù)測性。

2. C++標準庫提供的同步機制

C++11在標準庫中引入了 <thread><mutex> 等頭文件,提供了豐富的同步原語。

2.1 互斥量 - 保證互斥訪問

互斥量是最基礎(chǔ)的同步工具,它確保同一時間只有一個線程可以進入被保護的代碼段(臨界區(qū))。

a) std::mutex 最基本的互斥量,不可遞歸。

#include <iostream>
#include <thread>
#include <mutex>

std::mutex g_mutex;
int shared_data = 0;

void increment() {
    for (int i = 0; i < 100000; ++i) {
        g_mutex.lock(); // 加鎖
        ++shared_data;  // 臨界區(qū)
        g_mutex.unlock(); // 解鎖
    }
}

int main() {
    std::thread t1(increment);
    std::thread t2(increment);
    t1.join();
    t2.join();
    std::cout << "Final value: " << shared_data << std::endl; // 一定是 200000
    return 0;
}

注意:直接使用 lock()unlock() 是危險的,如果臨界區(qū)代碼拋出異常,可能導(dǎo)致互斥量無法解鎖,引發(fā)死鎖。永遠優(yōu)先使用RAII包裝器。

b) std::lock_guard 最簡單的RAII包裝器,在構(gòu)造時加鎖,析構(gòu)時自動解鎖。

void safe_increment() {
    for (int i = 0; i < 100000; ++i) {
        std::lock_guard<std::mutex> lock(g_mutex); // 構(gòu)造時加鎖
        ++shared_data; // 臨界區(qū)
    } // 作用域結(jié)束,lock析構(gòu),自動解鎖
}

c) std::unique_lock 比 lock_guard 更靈活,但開銷稍大。它允許延遲加鎖、提前解鎖、條件變量配合使用等。

void flexible_increment() {
    for (int i = 0; i < 100000; ++i) {
        std::unique_lock<std::mutex> lock(g_mutex, std::defer_lock); // 延遲加鎖
        // ... 一些不涉及共享數(shù)據(jù)的操作 ...
        lock.lock(); // 手動加鎖
        ++shared_data;
        lock.unlock(); // 可以手動提前解鎖
        // ... 其他操作 ...
    }
}

d) std::recursive_mutex 允許同一個線程多次獲取同一個互斥量而不會死鎖。用于可能遞歸調(diào)用或需要多次加鎖的場景。應(yīng)謹慎使用,通常表明設(shè)計可能有問題。

2.2 條件變量 - 線程間的通信與等待

條件變量允許線程阻塞等待某個條件成立,或在條件成立時通知其他線程。它必須與互斥量配合使用。

  • std::condition_variable (推薦,通常更高效)
  • std::condition_variable_any (可與任何滿足基本互斥量概念的類型一起使用,但開銷更大)

典型生產(chǎn)者-消費者模型:

#include <queue>
#include <condition_variable>

std::queue<int> g_queue;
std::mutex g_mutex;
std::condition_variable g_cv;
bool g_done = false;

void producer() {
    for (int i = 0; i < 10; ++i) {
        std::this_thread::sleep_for(std::chrono::milliseconds(100));
        {
            std::lock_guard<std::mutex> lock(g_mutex);
            g_queue.push(i);
            std::cout << "Produced: " << i << std::endl;
        }
        g_cv.notify_one(); // 通知一個等待的消費者
    }
    {
        std::lock_guard<std::mutex> lock(g_mutex);
        g_done = true;
    }
    g_cv.notify_all(); // 通知所有消費者結(jié)束
}

void consumer(int id) {
    while (true) {
        std::unique_lock<std::mutex> lock(g_mutex);
        // 等待條件:隊列不為空或生產(chǎn)結(jié)束
        g_cv.wait(lock, [] { return !g_queue.empty() || g_done; });

        // 被喚醒后,需要重新檢查條件
        if (g_done && g_queue.empty()) {
            break;
        }

        // 消費數(shù)據(jù)
        int data = g_queue.front();
        g_queue.pop();
        lock.unlock(); // 盡早釋放鎖

        std::cout << "Consumer " << id << " consumed: " << data << std::endl;
    }
}

關(guān)鍵點

  • wait 操作會原子地釋放互斥鎖并使線程休眠。
  • 被喚醒時,它會重新獲取互斥鎖,然后檢查條件(使用提供的謂詞)。必須使用循環(huán)或帶謂詞的wait來防止“虛假喚醒”。

2.3 信號量 - C++20

信號量是一個更底層的同步原語,它維護一個計數(shù)器,用于控制對特定數(shù)量資源的訪問。

  • std::counting_semaphore:允許至少 LeastMaxValue 個并發(fā)訪問。
  • std::binary_semaphore:是 std::counting_semaphore<1> 的別名,類似于互斥量,但可由不同線程進行鎖和解鎖。
#include <semaphore>

std::binary_semaphore smph(0); // 初始值為0

void waiter() {
    std::cout << "Waiting...\n";
    smph.acquire(); // 等待信號量值>0,然后減1
    std::cout << "Finished waiting!\n";
}

void notifier() {
    std::this_thread::sleep_for(std::chrono::seconds(1));
    std::cout << "Notifying...\n";
    smph.release(); // 信號量值加1,喚醒等待者
}

2.4 鎖存器和屏障 - C++20

用于管理一組線程的同步點。

  • std::latch:一次性使用的倒計時門閂。線程在 arrive_and_wait 上阻塞,直到內(nèi)部計數(shù)器減為0,所有阻塞線程被同時釋放。不可重復(fù)使用。
  • std::barrier:可重復(fù)使用的同步機制。它允許一組線程執(zhí)行一系列階段。在每個階段,線程到達屏障并阻塞,直到所有線程都到達,然后所有線程被釋放,屏障進入下一個階段。

3. 高級話題與底層原理

3.1 死鎖與預(yù)防

死鎖通常發(fā)生在兩個或以上線程互相等待對方持有的資源時。

產(chǎn)生條件(四個必要條件)

  1. 互斥訪問
  2. 持有并等待
  3. 不可剝奪
  4. 循環(huán)等待

預(yù)防策略

  • 固定順序上鎖:所有線程都按照相同的全局順序獲取鎖。
  • 使用 std::lock 或 std::scoped_lock (C++17):一次性鎖定多個互斥量,避免死鎖。
    std::mutex mutex1, mutex2;
    void safe_lock() {
        // std::lock 使用死鎖避免算法(如Dijkstra算法)來同時鎖定多個互斥量
        std::lock(mutex1, mutex2);
        // 使用 std::adopt_lock 表示互斥量已被鎖定,lock_guard只需接管所有權(quán)
        std::lock_guard<std::mutex> lock1(mutex1, std::adopt_lock);
        std::lock_guard<std::mutex> lock2(mutex2, std::adopt_lock);
        // ...
    }
    // C++17 更簡潔的方式:
    void safer_lock() {
        std::scoped_lock lock(mutex1, mutex2); // 自動使用死鎖避免算法
        // ...
    }
    
  • 避免嵌套鎖:如果可能,盡量只持有一個鎖。
  • 使用層次鎖:為鎖分配層級編號,只允許以編號遞減的順序獲取鎖。

3.2 性能考量

  • 鎖的粒度:鎖保護的臨界區(qū)應(yīng)盡可能小。在臨界區(qū)內(nèi)不要進行耗時操作(如I/O)。
  • 鎖競爭:當(dāng)多個線程頻繁嘗試獲取同一個鎖時,會發(fā)生激烈競爭,導(dǎo)致大量線程在用戶態(tài)和內(nèi)核態(tài)之間切換,嚴重降低性能。
    • 解決方案:使用無鎖數(shù)據(jù)結(jié)構(gòu)、減少共享數(shù)據(jù)、使用讀寫鎖(std::shared_mutex)、或者將數(shù)據(jù)分區(qū)(每個線程處理自己的數(shù)據(jù)副本,最后再合并)。

3.3 內(nèi)存模型與原子操作

同步機制的底層與C++內(nèi)存模型緊密相關(guān)。

  • std::atomic:提供了無需互斥鎖的線程安全訪問。對于基本數(shù)據(jù)類型(如 int, bool, pointer),使用 std::atomic 通常比 mutex 效率更高,因為它直接在CPU指令級別保證操作的原子性。
    std::atomic<int> atomic_counter(0);
    void atomic_increment() {
        for (int i = 0; i < 100000; ++i) {
            atomic_counter.fetch_add(1, std::memory_order_relaxed);
        }
    }
    
  • 內(nèi)存序std::memory_order 允許你控制原子操作周圍的非原子內(nèi)存訪問的可見性順序。這是為了在保證正確性的前提下,追求極致的性能。
    • memory_order_seq_cst(順序一致性):最強保證,默認選項,性能開銷最大。
    • memory_order_acquire/memory_order_release/memory_order_acq_rel:用于實現(xiàn)“同步于”關(guān)系。
    • memory_order_relaxed:只保證原子性,不提供同步和順序保證。

除非你是專家,否則請使用 std::atomic 的默認內(nèi)存序(memory_order_seq_cst)。

4. 總結(jié)與最佳實踐

  1. 優(yōu)先使用RAII:始終使用 std::lock_guard, std::unique_lock, std::scoped_lock,避免手動 lock/unlock。
  2. 用互斥量保護數(shù)據(jù),而非代碼:清晰地知道哪些數(shù)據(jù)是共享的,并用最小的鎖粒度來保護它。
  3. 慎用遞歸鎖:遞歸鎖通常意味著糟糕的設(shè)計。
  4. 使用條件變量進行事件等待:不要使用忙等待(while (!condition) {}),這會浪費CPU資源。
  5. 警惕死鎖:使用鎖順序、std::lock 等策略來預(yù)防。
  6. 性能瓶頸在于鎖競爭:優(yōu)化方向是減少共享和縮小臨界區(qū),而非盲目追求“無鎖”。無鎖編程極其復(fù)雜且容易出錯。
  7. 簡單場景用 atomic,復(fù)雜同步用 mutex:對于簡單的計數(shù)器或標志位,std::atomic 是更好的選擇。對于復(fù)雜的對象或需要等待條件的情況,使用 mutex 和 condition_variable。
  8. 理解工具適用場景
    • mutex:互斥訪問。
    • condition_variable:等待條件成立。
    • semaphore:控制資源池訪問。
    • latch/barrier:多線程分階段協(xié)同。

通過深入理解這些同步機制的原理、代價和適用場景,你才能寫出既正確又高效的多線程C++程序。

到此這篇關(guān)于淺析C++中的線程同步機制的實現(xiàn)那的文章就介紹到這了,更多相關(guān)C++ 線程同步機制內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • TCP與UDP協(xié)議的Socket編程詳解(附詳細示例)

    TCP與UDP協(xié)議的Socket編程詳解(附詳細示例)

    scoket編程即套接字編程,是網(wǎng)絡(luò)編程的基礎(chǔ),它允許兩臺或者多臺計算機進行網(wǎng)絡(luò)通信,這篇文章主要介紹了TCP與UDP協(xié)議的Socket編程的相關(guān)資料,需要的朋友可以參考下
    2025-08-08
  • C++如何用智能指針管理內(nèi)存資源

    C++如何用智能指針管理內(nèi)存資源

    這篇文章主要介紹了C++如何用智能指針管理內(nèi)存資源,幫助大家更好的理解和使用c++開發(fā),感興趣的朋友可以了解下
    2020-08-08
  • C語言鄰接表建立圖詳解

    C語言鄰接表建立圖詳解

    這篇文章主要介紹了C語言鄰接表建立圖,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2021-08-08
  • 一文詳解Qt的QObject類

    一文詳解Qt的QObject類

    Qt的QObject類是Qt框架中的基類,它是所有Qt對象的父類,本文主要介紹了Qt的QObject類,具有一定的參考價值,感興趣的可以了解一下
    2023-09-09
  • C語言使用結(jié)構(gòu)體實現(xiàn)簡單通訊錄

    C語言使用結(jié)構(gòu)體實現(xiàn)簡單通訊錄

    這篇文章主要為大家詳細介紹了C語言使用結(jié)構(gòu)體實現(xiàn)簡單通訊錄,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2018-02-02
  • 使用C++實現(xiàn)跨進程安全的文件讀寫鎖

    使用C++實現(xiàn)跨進程安全的文件讀寫鎖

    在多進程系統(tǒng)中,文件的并發(fā)讀寫可能導(dǎo)致數(shù)據(jù)競爭、文件損壞等問題,為了確保多個進程能夠安全地訪問同一文件,我們需要使用文件鎖,本文將介紹如何使用 C++ 實現(xiàn)文件鎖,并確保文件的并發(fā)讀寫操作是安全的,需要的朋友可以參考下
    2025-02-02
  • C++開發(fā)繪制正弦曲線的方法

    C++開發(fā)繪制正弦曲線的方法

    這篇文章主要為大家詳細介紹了C++繪制正弦曲線的方法,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2019-06-06
  • 如何使用C語言實現(xiàn)平衡二叉樹數(shù)據(jù)結(jié)構(gòu)算法

    如何使用C語言實現(xiàn)平衡二叉樹數(shù)據(jù)結(jié)構(gòu)算法

    對于判斷是否為平衡二叉樹而言,我們需要知道以下特性:是一個二叉樹也是一個二叉排序樹該樹的每個結(jié)點上的(深度)左子樹 - 右子樹的值為平衡因子(BF(Balance Factor))該樹的每一個節(jié)點的左子樹和右子樹的高度至多等于1(平衡因子只可能是-1,0,1)
    2021-08-08
  • C++ 類和對象從基礎(chǔ)語法到高級特性深度解析

    C++ 類和對象從基礎(chǔ)語法到高級特性深度解析

    本文深入探討了C++類和對象的核心概念,包括類的定義、訪問控制、實例化、this指針、默認成員函數(shù)(構(gòu)造、析構(gòu)、拷貝構(gòu)造、賦值重載)、以及高級特性,感興趣的朋友跟隨小編一起看看吧
    2026-01-01
  • C++ odr用法案例詳解

    C++ odr用法案例詳解

    這篇文章主要介紹了C++ odr用法案例詳解,本篇文章通過簡要的案例,講解了該項技術(shù)的了解與使用,以下就是詳細內(nèi)容,需要的朋友可以參考下
    2021-09-09

最新評論

芜湖县| 琼海市| 留坝县| 增城市| 荣昌县| 陇南市| 宝兴县| 正镶白旗| 鲁甸县| 龙川县| 高碑店市| 白朗县| 雷波县| 塘沽区| 开鲁县| 安塞县| 水城县| 龙陵县| 黄陵县| 江口县| 孟州市| 六安市| 莫力| 兴文县| 永州市| 呈贡县| 南靖县| 南江县| 肃北| 龙岩市| 双牌县| 鄱阳县| 丹江口市| 黄浦区| 雷波县| 夹江县| 山阴县| 临海市| 大理市| 鲜城| 石柱|