成人免费xxxxx在线视频软件_久久精品久久久_亚洲国产精品久久久_天天色天天色_亚洲人成一区_欧美一级欧美三级在线观看

C++11 鎖機制三兄弟大比拼:mutex、lock_guard 與 unique_lock

開發
今天我要用最接地氣的方式,幫你徹底搞懂 C++11 中的三兄弟:mutex、lock_guard和unique_lock。

大家好啊,我是小康。今天咱們聊點"家常"——那些讓C++程序員又愛又恨的多線程同步工具!

如果你曾經被多線程搞得頭大,或者聽到"死鎖"就心慌,那這篇文章就是為你準備的。今天我要用最接地氣的方式,幫你徹底搞懂C++11中的三兄弟:mutex、lock_guard和unique_lock。

為啥要用這些同步工具?

先別急著學怎么用,咱們得先知道為啥要用啊!

想象一下:你和室友共用一個衛生間。如果你們同時沖進去...嗯,畫面太美不敢想象。所以你們會怎么做?肯定是先看看有沒有人,沒人才進去,然后反鎖門,用完了再開門。

多線程程序也一樣!不同的線程可能會同時訪問同一塊"地盤"(共享資源),如果不加控制,就會出現數據錯亂、程序崩潰等一系列災難。

這時候,我們的三兄弟就閃亮登場了!

老大:mutex(互斥鎖)

mutex就像那個衛生間的門鎖,它是最基礎的同步工具,核心功能就兩個:鎖上(lock)和開鎖(unlock)。

來看個最簡單的例子:

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

std::mutex mtx;  // 這就是我們的"門鎖"
int shared_value = 0;  // 這是我們要保護的"衛生間"

void increment_value() {
    mtx.lock();  // 進去之前先鎖門
    std::cout << "線程 " << std::this_thread::get_id() << " 進入臨界區" << std::endl;
    
    // 想象這是個很復雜的操作,需要一些時間
    shared_value++;
    std::this_thread::sleep_for(std::chrono::milliseconds(100));
    
    std::cout << "線程 " << std::this_thread::get_id() << " 即將離開,共享值為: " << shared_value << std::endl;
    mtx.unlock();  // 用完了記得開鎖,讓別人能進來
}

int main() {
    std::thread t1(increment_value);
    std::thread t2(increment_value);
    
    t1.join();
    t2.join();
    
    return 0;
}

看著挺簡單對吧?但這有個大坑——如果在lock和unlock之間發生了異常,或者你單純忘記了unlock,那么鎖就永遠不會被釋放,其他線程永遠進不了"衛生間"!這就是傳說中的"死鎖"。

正因如此,直接使用mutex很容易出錯,所以C++11給我們提供了更智能的解決方案。

老二:lock_guard(保安大哥)

lock_guard就像一個靠譜的保安大哥。當你進"衛生間"時,他會自動鎖門;當你出來時,無論是正常出來還是因為突發情況(異常)跑出來,他都會負責解鎖。

看看用lock_guard如何改寫上面的例子:

void safer_increment() {
    std::lock_guard<std::mutex> guard(mtx);  // 保安上崗,自動鎖門
    
    std::cout << "線程 " << std::this_thread::get_id() << " 進入臨界區" << std::endl;
    
    // 即使這里拋出異常,離開函數作用域時lock_guard也會自動解鎖
    shared_value++;
    std::this_thread::sleep_for(std::chrono::milliseconds(100));
    
    std::cout << "線程 " << std::this_thread::get_id() << " 即將離開,共享值為: " << shared_value << std::endl;
    
    // 不需要手動解鎖,guard離開作用域時會自動解鎖
}

是不是簡單多了?這就是RAII(資源獲取即初始化)的魅力——資源的管理跟對象的生命周期綁定在一起。lock_guard一旦創建就會鎖定互斥量,一旦銷毀(離開作用域)就會解鎖互斥量。

不過lock_guard有個局限性:一旦上鎖,在其生命周期內你就不能手動解鎖了。就像你請了個特別死板的保安,他堅持要等你徹底離開才會開門,中途想出去透個氣都不行。

老三:unique_lock(萬能管家)

如果說lock_guard是保安大哥,那unique_lock就是一個高級管家,不但能自動鎖門解鎖,還能根據你的指令隨時鎖門或開門,甚至可以"借"鑰匙給別人。

來看個例子:

void flexible_operation() {
    std::unique_lock<std::mutex> superlock(mtx);  // 默認情況下構造時會鎖定mutex
    
    std::cout << "線程 " << std::this_thread::get_id() << " 開始工作" << std::endl;
    shared_value++;
    
    // 假設這里不需要鎖了,可以提前解鎖
    superlock.unlock();
    std::cout << "臨時解鎖,執行一些不需要保護的操作" << std::endl;
    std::this_thread::sleep_for(std::chrono::milliseconds(50));
    
    // 需要再次訪問共享資源時,可以重新上鎖
    superlock.lock();
    shared_value++;
    std::cout << "線程 " << std::this_thread::get_id() << " 完成工作,共享值為: " << shared_value << std::endl;
    
    // 同樣,不需要手動解鎖,離開作用域時會自動解鎖(如果當時處于鎖定狀態)
}

除了手動lock和unlock,unique_lock還有更多高級功能:

std::unique_lock<std::mutex> master_lock(mtx, std::defer_lock);  // 創建時不鎖定
if (master_lock.try_lock()) {  // 嘗試鎖定,如果失敗也不會阻塞
    std::cout << "成功獲取鎖!" << std::endl;
} else {
    std::cout << "獲取鎖失敗,但我可以去做別的事" << std::endl;
}

// 還可以配合條件變量使用
std::condition_variable cv;
std::unique_lock<std::mutex> lock(mtx);
cv.wait(lock, []{ return ready; });  // 這里會自動解鎖并等待條件滿足

unique_lock比lock_guard靈活,但也付出了一點性能代價,它內部需要維護更多狀態信息。

三兄弟大比拼

說了這么多,來個簡單對比:

特性

mutex

lock_guard

unique_lock

手動鎖定/解鎖

?

?

?

異常安全

?(需手動保證)

?

?

條件變量配合

?

?

?

嘗試鎖定(try_lock)

?

?

?

性能開銷

最小

很小

稍大

使用難度

容易出錯

簡單安全

靈活但復雜

實戰:模擬ATM取款與系統維護

最后用一個貼近生活的例子來鞏固一下。假設我們有個ATM系統,既要處理用戶取款,又要處理銀行的系統維護:

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

class ATMSystem {
private:
    double cash_available;  // ATM中可用現金
    bool maintenance_mode;  // 是否處于維護模式
    std::mutex mtx;
    std::condition_variable cv;  // 條件變量,用于等待維護結束

public:
    ATMSystem(double initial_cash) : cash_available(initial_cash), maintenance_mode(false) {}
    
    // 用戶取款操作
    bool withdraw(double amount) {
        // 這里必須用unique_lock,因為條件變量wait需要它
        std::unique_lock<std::mutex> lock(mtx);
        
        // 如果ATM正在維護中,等待維護結束
        cv.wait(lock, [this] { return !maintenance_mode; });
        
        // 檢查余額并取款
        if (cash_available >= amount) {
            std::this_thread::sleep_for(std::chrono::milliseconds(50));
            cash_available -= amount;
            std::cout << "取出: " << amount << ",ATM剩余現金: " << cash_available << std::endl;
            return true;
        }
        
        std::cout << "ATM現金不足,取款失敗!當前剩余: " << cash_available << std::endl;
        return false;
    }
    
    // 開始系統維護
    void start_maintenance() {
        std::lock_guard<std::mutex> guard(mtx);
        maintenance_mode = true;
        std::cout << "ATM進入維護模式,暫停服務" << std::endl;
    }
    
    // 結束系統維護
    void end_maintenance() {
        {
            std::lock_guard<std::mutex> guard(mtx);
            maintenance_mode = false;
            std::cout << "ATM維護完成,恢復服務" << std::endl;
        }
        // 通知所有等待的取款線程
        cv.notify_all();
    }
    
    // 補充現金
    void refill_cash(double amount) {
        std::lock_guard<std::mutex> guard(mtx);
        cash_available += amount;
        std::cout << "ATM補充現金: " << amount << ",當前總現金: " << cash_available << std::endl;
    }
};

// 模擬用戶線程
void user_thread(ATMSystem& atm, int user_id) {
    std::cout << "用戶 " << user_id << " 嘗試取款..." << std::endl;
    atm.withdraw(100);
}

// 模擬維護線程
void maintenance_thread(ATMSystem& atm) {
    std::this_thread::sleep_for(std::chrono::milliseconds(20));
    atm.start_maintenance();
    
    // 執行維護操作
    std::this_thread::sleep_for(std::chrono::milliseconds(300));
    atm.refill_cash(500);
    
    // 維護結束
    atm.end_maintenance();
}

int main() {
    ATMSystem atm(300);  // 初始現金300元
    
    // 啟動一個維護線程和多個用戶線程
    std::thread maint(maintenance_thread, std::ref(atm));
    
    std::vector<std::thread> users;
    for (int i = 1; i <= 5; ++i) {
        users.push_back(std::thread(user_thread, std::ref(atm), i));
    }
    
    // 等待所有線程結束
    maint.join();
    for (auto& t : users) {
        t.join();
    }
    
    return 0;
}

總結

  • mutex:最基礎的鎖,需要手動鎖定和解鎖,用不好容易出問題,就像自己管理衛生間門鎖。
  • lock_guard:簡單安全的自動鎖,構造時鎖定,析構時解鎖,但不能中途操作鎖狀態,就像請了個死板但可靠的保安。
  • unique_lock:功能最全面的鎖包裝器,靈活性最高,但有輕微的性能開銷,就像一個萬能的管家。

優秀實踐:

  • 簡單場景,優先使用lock_guard
  • 需要條件變量或靈活鎖定/解鎖時,使用unique_lock
  • 對性能極度敏感的場景,考慮直接使用mutex,但要非常小心

希望這篇文章能讓你對C++11的同步工具有個清晰的認識。多線程不再可怕,熟練掌握這"三兄弟",你就能寫出安全高效的并發程序啦!

責任編輯:趙寧寧 來源: 跟著小康學編程
相關推薦

2019-08-27 09:00:00

敏捷開發開發方法項目

2010-04-21 12:54:46

Unix內核

2023-05-26 15:53:48

MidjourneyAI圖像

2011-01-19 11:10:30

2009-07-02 18:50:43

2009-10-13 14:46:00

思科認證

2010-07-14 13:38:51

Perl開發工具

2020-08-04 17:06:40

Merging Rebasing Git

2010-03-18 14:54:46

主流無線技術

2019-11-21 09:39:30

EMonitorCAT監控

2016-11-02 09:20:01

SparkHadoop MapR大數據

2011-08-18 11:08:02

2013-09-25 10:09:54

閃存SSD存儲

2018-11-15 10:23:18

路由器類別作用

2011-11-28 12:55:37

JavaJVM

2019-03-29 08:25:21

JSONXML前端

2018-10-25 14:08:07

KubernetesGoogle

2011-04-01 09:18:01

MRTGCactiZabbix

2012-08-15 09:26:54

虛擬化

2010-09-07 17:24:44

DB2數據庫
點贊
收藏

51CTO技術棧公眾號

主站蜘蛛池模板: 亚洲国产一区二区三区在线观看 | 欧洲亚洲精品久久久久 | 黄色中文字幕 | av网址在线播放 | 亚洲国产第一页 | 亚洲国产精品一区二区第一页 | 亚洲乱码一区二区三区在线观看 | 日韩免费中文字幕 | 日韩a视频| 久久高清 | 中文字幕视频在线 | 在线观看国产视频 | 亚洲人免费视频 | 中文字字幕在线中文乱码范文 | 成人精品鲁一区一区二区 | 中文字幕在线不卡播放 | 99久久国产综合精品麻豆 | 国产亚洲欧美另类一区二区三区 | 国产精品夜间视频香蕉 | 中文字幕一页二页 | 久草在线中文888 | 国产 欧美 日韩 一区 | 欧美一级免费看 | 色秀网站 | 久草久草久草 | 国产在线观看一区 | 欧美日韩中文国产一区发布 | 欧美性网 | 日韩欧美中文 | 亚洲精品一区二区在线观看 | 久久久激情视频 | 超碰人人91| 四虎成人免费视频 | 999国产精品视频 | 一级欧美日韩 | 一级做a爰片久久毛片免费看 | 色婷婷综合久久久中字幕精品久久 | 国产欧美精品区一区二区三区 | 午夜电影网 | 国产精品久久久久免费 | 欧美激情国产精品 |