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

C++ 多線程同步之互斥鎖(mutex)實戰(zhàn)指南

 更新時間:2026年05月18日 11:06:22   作者:小林說AI  
本文介紹了C++標準庫中互斥鎖的基本用法,主要了std::mutex與std::lock_guard的使用方法,解釋了死鎖的產(chǎn)生原因及規(guī)避方法,并通過實際案例展示了如何解決多線程環(huán)境下的資源競爭問題,感興趣的朋友一起看看吧

?? 學習目標:掌握 C++ 標準庫中互斥鎖的基本用法,理解多線程同步的核心原理,能夠解決多線程環(huán)境下的資源競爭問題。
?? 學習重點std::mutexstd::lock_guard 的使用、死鎖的產(chǎn)生原因及規(guī)避方法、實際場景中的同步案例實現(xiàn)。

48.1 多線程同步的必要性

在多線程編程中,當多個線程同時訪問共享資源時,會出現(xiàn)資源競爭問題。
例如兩個線程同時對同一個變量進行讀寫操作,會導致最終結果與預期不符。
這種問題被稱為線程安全問題,而解決該問題的核心就是線程同步

?? 注意事項:線程不同步會引發(fā)數(shù)據(jù)競爭,造成程序運行結果不可預測,甚至導致程序崩潰。

舉個簡單的反例,兩個線程同時對全局變量 count 進行自增操作:

#include <iostream>
#include <thread>
using namespace std;
int count = 0;
void increment() {
    for (int i = 0; i < 100000; ++i) {
        count++; // 非原子操作,存在數(shù)據(jù)競爭
    }
}
int main() {
    thread t1(increment);
    thread t2(increment);
    t1.join();
    t2.join();
    cout << "最終 count 值:" << count << endl;
    return 0;
}

運行該程序會發(fā)現(xiàn),最終 count 的值大概率小于 200000
這就是因為 count++ 不是原子操作,被兩個線程交替執(zhí)行打亂了執(zhí)行步驟。

48.2 C++ 標準庫中的互斥鎖

C++11 及以后的標準庫提供了 <mutex> 頭文件,封裝了多種互斥鎖相關的類。
最基礎且常用的就是 std::mutex。

48.2.1std::mutex的核心接口

  • lock():獲取互斥鎖。如果鎖已被其他線程占用,當前線程會阻塞等待。
  • unlock():釋放互斥鎖。必須與 lock() 成對使用。
  • try_lock():嘗試獲取互斥鎖。如果獲取失敗,不會阻塞,直接返回 false。

48.2.2std::lock_guard:自動管理鎖的生命周期

直接使用 lock()unlock() 容易出現(xiàn)遺漏解鎖的情況。
比如程序拋出異常時,unlock() 可能無法執(zhí)行,導致死鎖。
std::lock_guard 基于RAII 機制實現(xiàn),可以自動在構造時加鎖,析構時解鎖。

? 核心結論:實際開發(fā)中優(yōu)先使用 std::lock_guard,而非手動調(diào)用 lock()/unlock()。

48.3 互斥鎖實戰(zhàn):解決數(shù)據(jù)競爭問題

我們使用 std::mutexstd::lock_guard 改造 48.1 節(jié)的反例:

#include <iostream>
#include <thread>
#include <mutex>
using namespace std;
int count = 0;
mutex mtx; // 定義全局互斥鎖
void increment() {
    for (int i = 0; i < 100000; ++i) {
        lock_guard<mutex> lock(mtx); // 自動加鎖
        count++; // 臨界區(qū)代碼,此時只有一個線程能執(zhí)行
    } // lock_guard 析構,自動解鎖
}
int main() {
    thread t1(increment);
    thread t2(increment);
    t1.join();
    t2.join();
    cout << "最終 count 值:" << count << endl;
    return 0;
}

運行該程序,最終 count 的值穩(wěn)定等于 200000。
這說明互斥鎖成功保護了臨界區(qū)代碼,避免了數(shù)據(jù)競爭。

48.3.1 關鍵概念解釋

  • 臨界區(qū):需要被保護的、不能被多個線程同時執(zhí)行的代碼段。
    上例中 count++ 就是臨界區(qū)。
  • 互斥鎖的作用:保證同一時刻只有一個線程能進入臨界區(qū)。

48.4 死鎖的產(chǎn)生與規(guī)避

?? 死鎖:多個線程互相持有對方需要的鎖,導致所有線程都無法繼續(xù)執(zhí)行的狀態(tài)。

48.4.1 死鎖的四個必要條件

  1. 互斥條件:資源只能被一個線程占用。
  2. 請求與保持條件:線程持有一個資源的同時,請求其他線程持有的資源。
  3. 不可剝奪條件:線程已持有的資源不能被其他線程強制奪走。
  4. 循環(huán)等待條件:多個線程形成首尾相接的循環(huán)等待資源關系。

48.4.2 死鎖的示例

兩個線程分別持有一個鎖,同時請求對方的鎖:

#include <iostream>
#include <thread>
#include <mutex>
using namespace std;
mutex mtx1, mtx2;
void thread1() {
    mtx1.lock();
    this_thread::sleep_for(chrono::milliseconds(100)); // 確保 thread2 先拿到 mtx2
    mtx2.lock(); // 等待 mtx2,此時 thread2 持有 mtx2 并等待 mtx1
    cout << "thread1 執(zhí)行完畢" << endl;
    mtx2.unlock();
    mtx1.unlock();
}
void thread2() {
    mtx2.lock();
    this_thread::sleep_for(chrono::milliseconds(100)); // 確保 thread1 先拿到 mtx1
    mtx1.lock(); // 等待 mtx1,此時 thread1 持有 mtx1 并等待 mtx2
    cout << "thread2 執(zhí)行完畢" << endl;
    mtx1.unlock();
    mtx2.unlock();
}
int main() {
    thread t1(thread1);
    thread t2(thread2);
    t1.join();
    t2.join();
    return 0;
}

運行該程序,兩個線程會互相等待,陷入死鎖狀態(tài),無法輸出任何內(nèi)容。

48.4.3 規(guī)避死鎖的常用方法

  1. 固定鎖的獲取順序:所有線程按照相同的順序獲取鎖。
    比如上例中,讓兩個線程都先獲取 mtx1,再獲取 mtx2。
  2. 使用 std::lock 同時獲取多個鎖:std::lock 可以一次性獲取多個互斥鎖,避免循環(huán)等待。
  3. 使用帶超時的鎖嘗試:通過 try_lock()std::timed_mutex,在超時后放棄獲取鎖,避免永久阻塞。

48.5 實戰(zhàn)案例:多線程售票系統(tǒng)

模擬一個售票系統(tǒng),多個窗口同時售票,使用互斥鎖保證票數(shù)不會出現(xiàn)負數(shù)或重復售票的情況。

#include <iostream>
#include <thread>
#include <mutex>
#include <vector>
using namespace std;
int tickets = 100; // 總票數(shù)
mutex mtx;
// 售票函數(shù)
void sell_tickets(int window_id) {
    while (true) {
        lock_guard<mutex> lock(mtx);
        if (tickets > 0) {
            cout << "窗口" << window_id << "售出第" << tickets << "張票" << endl;
            tickets--;
            this_thread::sleep_for(chrono::milliseconds(50)); // 模擬售票耗時
        } else {
            break;
        }
    }
    cout << "窗口" << window_id << "售票結束" << endl;
}
int main() {
    vector<thread> windows;
    // 創(chuàng)建 5 個售票窗口
    for (int i = 1; i <= 5; ++i) {
        windows.emplace_back(sell_tickets, i);
    }
    // 等待所有窗口售票結束
    for (auto& t : windows) {
        t.join();
    }
    cout << "所有票已售罄" << endl;
    return 0;
}

? 運行效果:5 個窗口有序售票,最終票數(shù)從 100 遞減到 0,不會出現(xiàn)重復售票或票數(shù)為負的情況。

48.6 本章小結

  1. 多線程訪問共享資源時必須進行同步,否則會出現(xiàn)數(shù)據(jù)競爭問題。
  2. std::mutex 是 C++ 最基礎的互斥鎖,搭配 std::lock_guard 可以安全地管理鎖的生命周期。
  3. 死鎖由四個必要條件引發(fā),通過固定鎖順序、使用 std::lock 等方法可以有效規(guī)避。
  4. 互斥鎖的核心是保護臨界區(qū),確保同一時刻只有一個線程能執(zhí)行臨界區(qū)代碼。

到此這篇關于C++ 多線程同步之互斥鎖(mutex)實戰(zhàn)的文章就介紹到這了,更多相關C++ 互斥鎖mutex內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!

相關文章

  • C++STL之vector模板類詳解

    C++STL之vector模板類詳解

    這篇文章主要為大家詳細介紹了C++vector模板類,文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下,希望能夠給你帶來幫助
    2022-03-03
  • C++通過自定義函數(shù)求一元二次方程的根

    C++通過自定義函數(shù)求一元二次方程的根

    這篇文章主要介紹了C++通過自定義函數(shù)求一元二次方程的根,涉及C++數(shù)學運算相關技巧,非常簡單實用,需要的朋友可以參考下
    2016-05-05
  • C語言數(shù)據(jù)結構的時間復雜度和空間復雜度

    C語言數(shù)據(jù)結構的時間復雜度和空間復雜度

    算法在編寫成可執(zhí)行程序后,運行時需要耗費時間資源和空間(內(nèi)存)資源 。因此衡量一個算法的好壞,一般是從時間和空間兩個維度來衡量的,即時間復雜度和空間復雜度,感興趣的同學可以參考閱讀
    2023-04-04
  • C++實現(xiàn)LeetCode(160.求兩個鏈表的交點)

    C++實現(xiàn)LeetCode(160.求兩個鏈表的交點)

    這篇文章主要介紹了C++實現(xiàn)LeetCode(160.求兩個鏈表的交點),本篇文章通過簡要的案例,講解了該項技術的了解與使用,以下就是詳細內(nèi)容,需要的朋友可以參考下
    2021-07-07
  • C/C++中OpenCV 矩陣運算的實現(xiàn)

    C/C++中OpenCV 矩陣運算的實現(xiàn)

    本文主要介紹了C/C++中OpenCV 矩陣運算的實現(xiàn),包括基本算術運算(標量與矩陣)、矩陣乘法、轉(zhuǎn)置、逆矩陣、行列式、跡、范數(shù)等操作,感興趣的可以了解一下
    2025-05-05
  • 解決在Mac下直接解壓C++靜態(tài)庫出現(xiàn)的問題

    解決在Mac下直接解壓C++靜態(tài)庫出現(xiàn)的問題

    最近在研究C++的各種編譯構建過程,學習了一下cmake,gyp/ninja這些自動化構建工具后,想著自己試下用純命令行跑一遍編譯流程。在試圖把C++靜態(tài)庫編譯為動態(tài)庫的過程中遇到了棘手的問題,找了好久后發(fā)現(xiàn)是跟Mac平臺相關的,這里記錄一下,望對遇到類似問題的童鞋有幫助。
    2016-12-12
  • 字符串的組合算法問題的C語言實現(xiàn)攻略

    字符串的組合算法問題的C語言實現(xiàn)攻略

    這篇文章主要介紹了字符串的組合算法問題的C語言實現(xiàn)攻略,是根據(jù)ACM總結的經(jīng)典算法問題,需要的朋友可以參考下
    2015-08-08
  • c++程序字符型的實例講解

    c++程序字符型的實例講解

    在本篇文章里小編給大家整理的是一篇關于
    2020-02-02
  • Qt使用SQLite數(shù)據(jù)庫實現(xiàn)數(shù)據(jù)增刪改查

    Qt使用SQLite數(shù)據(jù)庫實現(xiàn)數(shù)據(jù)增刪改查

    這篇文章主要為大家詳細介紹了Qt如何使用SQLite數(shù)據(jù)庫實現(xiàn)數(shù)據(jù)增刪改查功能,文中的示例代碼講解詳細,感興趣的小伙伴可以跟隨小編一起了解一下
    2023-06-06
  • C指針原理教程之Ncurses介紹

    C指針原理教程之Ncurses介紹

    Ncurses 提供字符終端處理庫,包括面板和菜單。為了能夠使用ncurses庫,您必須在您的源程序中將curses.h包括(include)進來,而且在編譯的需要與它連接起來. 在gcc中您可以使用參數(shù)-lcurses進行編譯.
    2019-02-02

最新評論

垫江县| 姚安县| 兰考县| 苍南县| 安塞县| 页游| 吉林省| 包头市| 德州市| 绵阳市| 宜都市| 龙山县| 阳信县| 新泰市| 仁化县| 宜丰县| 图木舒克市| 汨罗市| 吴桥县| 海丰县| 仁化县| 盐池县| 富平县| 奇台县| 辽阳市| 弥渡县| 武威市| 亳州市| 盐城市| 福清市| 长兴县| 舒兰市| 阳曲县| 民勤县| 曲沃县| 育儿| 泰顺县| 巴彦淖尔市| 改则县| 厦门市| 肃宁县|