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

C++多線程與鎖機制使用解讀

 更新時間:2026年04月10日 17:24:44   作者:當歸. z Z  
文章主要介紹了C++中的多線程編程知識,包括線程的創(chuàng)建、參數(shù)傳遞、線程休眠、互斥鎖、條件變量、原子操作、死鎖預防、線程局部存儲、讀寫鎖和自旋鎖等內(nèi)容,并給出了相應的實現(xiàn)方法和使用場景

1. 基本多線程編程

1.1 創(chuàng)建線程

#include <iostream>
#include <thread>

void thread_function() {
    std::cout << "Hello from thread!\n";
}

int main() {
    std::thread t(thread_function); // 創(chuàng)建并啟動線程
    t.join(); // 等待線程結(jié)束
    return 0;
}

1.2 帶參數(shù)的線程函數(shù)

#include <thread>
#include <iostream>

void print_num(int num) {
    std::cout << "Number: " << num << "\n";
}

int main() {
    std::thread t(print_num, 42);
    t.join();
    return 0;
}

1.3 join() 和 detach()

std::thread t(threadFunction);

// join() - 等待線程完成
t.join();

// detach() - 分離線程,線程獨立運行
// t.detach();

// 檢查線程是否可joinable
if (t.joinable()) {
    t.join();
}

1.4 獲取當前線程信息

#include <thread>
#include <iostream>

int main() {
    std::cout << "Main thread ID: " << std::this_thread::get_id() << std::endl;
    
    std::thread t([](){
        std::cout << "Worker thread ID: " << std::this_thread::get_id() << std::endl;
    });
    
    t.join();
    return 0;
}

1.5 線程休眠

#include <chrono>
#include <thread>

int main() {
    std::cout << "Sleeping for 2 seconds..." << std::endl;
    std::this_thread::sleep_for(std::chrono::seconds(2));
    std::cout << "Awake!" << std::endl;
    return 0;
}

2. mutex (互斥鎖)

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

std::mutex mtx; // 全局互斥鎖
int shared_data = 0;

void increment() {
    for (int i = 0; i < 100000; ++i) {
        mtx.lock();   // 上鎖
        ++shared_data;
        mtx.unlock(); // 解鎖
    }
}

int main() {
    std::thread t1(increment);
    std::thread t2(increment);
    
    t1.join();
    t2.join();
    
    std::cout << "Final value: " << shared_data << "\n";
    return 0;
}

2.1 lock_guard (自動管理鎖)

lock_guard 在構(gòu)造時自動上鎖,在析構(gòu)時自動解鎖,防止忘記解鎖

void increment_safe() {
    for (int i = 0; i < 100000; ++i) {
        std::lock_guard<std::mutex> lock(mtx); // 自動上鎖
        ++shared_data;
    } // 自動解鎖
}

2.2 unique_lock

unique_lock 比 lock_guard 更靈活,可以手動上鎖和解鎖。

void increment_flexible() {
    for (int i = 0; i < 100000; ++i) {
        std::unique_lock<std::mutex> lock(mtx);
        ++shared_data;
        lock.unlock(); // 可以手動解鎖
        // 做一些不需要鎖的操作
        lock.lock();   // 再手動上鎖
        ++shared_data;
    }
}

2.3 嘗試鎖try_lock()

void tryLockExample() {
    std::unique_lock<std::mutex> lock(mtx, std::try_to_lock);
    if (lock.owns_lock()) {
        // 成功獲取鎖
        std::cout << "Got the lock!\n";
    } else {
        // 未能獲取鎖
        std::cout << "Couldn't get the lock, doing something else...\n";
    }
}

2.4 遞歸互斥鎖std::recursive_mutex

#include <mutex>

std::recursive_mutex rec_mtx;

void recursiveFunction(int count) {
    std::lock_guard<std::recursive_mutex> lock(rec_mtx);
    if (count > 0) {
        std::cout << "Count: " << count << '\n';
        recursiveFunction(count - 1);
    }
}

int main() {
    std::thread t(recursiveFunction, 3);
    t.join();
    return 0;
}

2.5 定時互斥鎖std::timed_mutex

#include <mutex>
#include <chrono>

std::timed_mutex timed_mtx;

void timedLockExample() {
    auto timeout = std::chrono::milliseconds(100);
    
    if (timed_mtx.try_lock_for(timeout)) {
        // 在100ms內(nèi)成功獲取鎖
        std::this_thread::sleep_for(std::chrono::milliseconds(50));
        timed_mtx.unlock();
    } else {
        // 超時未能獲取鎖
        std::cout << "Could not get the lock within 100ms\n";
    }
}

2.6std::adopt_lock與std::defer_lock

特性std::adopt_lockstd::defer_lock
用途表示鎖已被當前線程獲得表示不立即獲取鎖
加鎖時機不嘗試加鎖(假設(shè)已鎖定)稍后手動加鎖
典型使用場景與 std::lock 配合使用延遲加鎖或條件加鎖
可用性適用于 lock_guard 和 unique_lock僅適用于 unique_lock

adopt_lock表示當前線程已經(jīng)獲得了互斥鎖的所有權(quán),不需要再嘗試加鎖

#include <mutex>

std::mutex mtx;

void function() {
    mtx.lock(); // 手動加鎖
    
    // 使用 adopt_lock 告訴 lock_guard 我們已經(jīng)擁有鎖
    std::lock_guard<std::mutex> lock(mtx, std::adopt_lock);
    
    // 臨界區(qū)代碼...
    // 離開作用域時自動解鎖
}

3. 條件變量 (condition_variable)

用于線程間的同步,允許線程等待特定條件成立。

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

std::mutex mtx;
std::condition_variable cv;
bool ready = false;

void worker() {
    std::unique_lock<std::mutex> lock(mtx);
    cv.wait(lock, []{ return ready; }); // 等待ready變?yōu)閠rue
    std::cout << "Worker is processing data\n";
}

int main() {
    std::thread t(worker);
    
    {
        std::lock_guard<std::mutex> lock(mtx);
        ready = true;
    }
    cv.notify_one(); // 通知等待的線程
    
    t.join();
    return 0;
}

3.1wait

std::unique_lock<std::mutex> lock(mtx);
cv.wait(lock); // 無條件等待,可能虛假喚醒

 帶謂詞的 wait()

cv.wait(lock, []{ return ready; }); // 等價于:
// while (!ready) {
//     cv.wait(lock);
// }

wait_for() - 帶超時等待

using namespace std::chrono_literals;
if (cv.wait_for(lock, 100ms, []{ return ready; })) {
    // 條件在超時前滿足
} else {
    // 超時
}

wait_until() - 等待到指定時間點

auto timeout = std::chrono::steady_clock::now() + 100ms;
if (cv.wait_until(lock, timeout, []{ return ready; })) {
    // 條件在時間點前滿足
} else {
    // 超時
}

3.2notify

notify_one() - 通知一個等待線程

{
    std::lock_guard<std::mutex> lock(mtx);
    ready = true;
}
cv.notify_one(); // 只喚醒一個等待線程

notify_all() - 通知所有等待線程

{
    std::lock_guard<std::mutex> lock(mtx);
    ready = true;
}
cv.notify_all(); // 喚醒所有等待線程

3.3 生產(chǎn)消費者模式示例

#include <queue>
#include <chrono>

std::mutex mtx;
std::condition_variable cv;
std::queue<int> data_queue;
const int MAX_SIZE = 10;

void producer() {
    for (int i = 0; i < 20; ++i) {
        std::unique_lock<std::mutex> lock(mtx);
        cv.wait(lock, []{ return data_queue.size() < MAX_SIZE; });
        
        data_queue.push(i);
        std::cout << "Produced: " << i << std::endl;
        
        lock.unlock();
        cv.notify_all();
        
        std::this_thread::sleep_for(std::chrono::milliseconds(100));
    }
}

void consumer() {
    while (true) {
        std::unique_lock<std::mutex> lock(mtx);
        cv.wait(lock, []{ return !data_queue.empty(); });
        
        int data = data_queue.front();
        data_queue.pop();
        std::cout << "Consumed: " << data << std::endl;
        
        lock.unlock();
        cv.notify_all();
        
        if (data == 19) break; // 結(jié)束條件
    }
}

int main() {
    std::thread p(producer);
    std::thread c(consumer);
    
    p.join();
    c.join();
    
    return 0;
}

4. 原子操作 (atomic)

對于簡單的數(shù)據(jù)類型,可以使用原子操作避免鎖的開銷。

#include <atomic>
#include <thread>
#include <iostream>

std::atomic<int> counter(0);

void increment_atomic() {
    for (int i = 0; i < 100000; ++i) {
        ++counter; // 原子操作,無需鎖
    }
}

int main() {
    std::thread t1(increment_atomic);
    std::thread t2(increment_atomic);
    
    t1.join();
    t2.join();
    
    std::cout << "Counter: " << counter << "\n";
    return 0;
}

4.1 基本原子類型

#include <atomic>

std::atomic<int> atomicInt(0);      // 原子整數(shù)
std::atomic<bool> atomicBool(false); // 原子布爾值
std::atomic<long> atomicLong;       // 默認初始化為0

4.2 加載和存儲

// 存儲值
atomicInt.store(42);                // 原子存儲
atomicInt = 42;                     // 等價寫法

// 加載值
int value = atomicInt.load();       // 原子加載
value = atomicInt;                  // 等價寫法

4.3 交換操作

int old = atomicInt.exchange(100);  // 原子交換為新值,返回舊值

4.4 讀-修改-寫操作

std::atomic<int> counter(0);

// 原子加法,返回舊值
int prev = counter.fetch_add(5);    // counter += 5,返回加前的值

// 原子減法
prev = counter.fetch_sub(3);       // counter -= 3,返回減前的值
std::atomic<int> flags(0);

flags.fetch_or(0x01);   // 原子按位或
flags.fetch_and(~0x01); // 原子按位與
flags.fetch_xor(0x03);  // 原子按位異或

4.5 比較交換 (CAS)

std::atomic<int> value(10);
int expected = 10;

// 比較并交換
bool success = value.compare_exchange_weak(expected, 20);
// 如果value == expected,則設(shè)置為20,返回true
// 否則將expected更新為當前value,返回false

// 強版本 (較少虛假失敗)
success = value.compare_exchange_strong(expected, 30);

4.6 內(nèi)存順序 (Memory Order)

// 默認是最嚴格的內(nèi)存順序 (sequential consistency)
atomicInt.store(42, std::memory_order_seq_cst);

// 寬松內(nèi)存順序
atomicInt.store(42, std::memory_order_relaxed);

// 常見內(nèi)存順序:
// - memory_order_relaxed: 無順序保證
// - memory_order_consume: 數(shù)據(jù)依賴順序
// - memory_order_acquire: 讀操作,防止上方讀寫重排
// - memory_order_release: 寫操作,防止下方讀寫重排
// - memory_order_acq_rel: 讀-修改-寫操作
// - memory_order_seq_cst: 順序一致性 (默認)

4.7 原子標志

std::atomic_flag flag = ATOMIC_FLAG_INIT; // 必須這樣初始化

// 測試并設(shè)置 (原子操作)
bool was_set = flag.test_and_set();

// 清除標志
flag.clear();

4.8 原子指針

class MyClass {};
MyClass* ptr = new MyClass();
std::atomic<MyClass*> atomicPtr(ptr);

// 原子指針操作
MyClass* old = atomicPtr.exchange(new MyClass());

// 比較交換指針
MyClass* expected = old;
atomicPtr.compare_exchange_strong(expected, nullptr);

4.9 自定義原子類型

struct Point { int x; int y; };
std::atomic<Point> atomicPoint{Point{1, 2}};

// 必須是可平凡復制的類型(trivially copyable)
static_assert(std::is_trivially_copyable<Point>::value, 
              "Point must be trivially copyable");
// 原子操作示例
Point old = atomicPoint.load();          // 原子讀取
atomicPoint.store(Point{3, 4});         // 原子寫入
Point newVal{5, 6};
Point expected{3, 4};
atomicPoint.compare_exchange_strong(expected, newVal); // CAS操作

std::atomic 對模板類型 T 的關(guān)鍵要求是:

  • 可平凡復制(Trivially Copyable):保證對象可以用 memcpy 方式安全復制
  • 無用戶定義的拷貝控制(析構(gòu)函數(shù)、拷貝/移動構(gòu)造/賦值)
  • 標準布局(Standard Layout)

static_assert 在編譯時驗證這些條件,若不滿足會立即報錯(比運行時錯誤更安全)。

 一個類型 T 是 平凡可復制(Trivially Copyable) 的,當且僅當滿足以下所有條件:

  • 沒有用戶定義的拷貝構(gòu)造函數(shù)(T(const T&)
  • 沒有用戶定義的移動構(gòu)造函數(shù)(T(T&&)
  • 沒有用戶定義的拷貝賦值運算符(T& operator=(const T&)
  • 沒有用戶定義的移動賦值運算符(T& operator=(T&&)
  • 有一個平凡的(隱式定義的或 =default)析構(gòu)函數(shù)
  • 所有非靜態(tài)成員和基類也必須是平凡可復制的
  • 不能有虛函數(shù)或虛基類

如果滿足這些條件,編譯器可以安全地使用 memcpy 來復制該類型的對象,而不會引發(fā)未定義行為(UB)。

5. 死鎖預防

當多個線程需要多個鎖時,可能產(chǎn)生死鎖。

預防方法:

  • 總是以相同的順序獲取鎖
  • 使用 std::lock 同時鎖定多個互斥量
std::mutex mtx1, mtx2;

void safe_lock() {
    // 同時鎖定兩個互斥量,避免死鎖
    std::lock(mtx1, mtx2);
    std::lock_guard<std::mutex> lock1(mtx1, std::adopt_lock);
    std::lock_guard<std::mutex> lock2(mtx2, std::adopt_lock);
    // 安全地訪問共享資源
}

6. 線程局部存儲 (thread_local)

使用 thread_local 關(guān)鍵字聲明線程局部變量,每個線程有自己的副本。

#include <thread>
#include <iostream>

thread_local int thread_specific_value = 0;

void thread_function(int id) {
    thread_specific_value = id;
    std::cout << "Thread " << id << ": " << thread_specific_value << "\n";
}

int main() {
    std::thread t1(thread_function, 1);
    std::thread t2(thread_function, 2);
    
    t1.join();
    t2.join();
    
    return 0;
}

7. 讀寫鎖

讀寫鎖是一種特殊的同步機制,允許多個讀操作并發(fā)執(zhí)行,但寫操作必須獨占訪問。這種鎖在"讀多寫少"的場景下能顯著提高性能。

C++17 中的std::shared_mutex

#include <shared_mutex>
#include <vector>

class ThreadSafeContainer {
private:
    std::vector<int> data;
    mutable std::shared_mutex mutex; // mutable 允許const方法加鎖
    
public:
    // 讀操作 - 使用共享鎖
    int get(size_t index) const {
        std::shared_lock<std::shared_mutex> lock(mutex);
        return data.at(index);
    }
    
    // 寫操作 - 使用獨占鎖
    void set(size_t index, int value) {
        std::unique_lock<std::shared_mutex> lock(mutex);
        data.at(index) = value;
    }
    
    // 批量讀操作示例
    std::vector<int> getSnapshot() const {
        std::shared_lock<std::shared_mutex> lock(mutex);
        return data;
    }
};

讀寫鎖特性

三種訪問模式

  • 共享讀鎖 (shared_lock):多個線程可同時持有
  • 獨占寫鎖 (unique_lock):只有一個線程可持有
  • 升級鎖 (C++14沒有直接支持,需手動實現(xiàn))

鎖的優(yōu)先級策略

  • 讀優(yōu)先:容易導致寫線程饑餓
  • 寫優(yōu)先:可能降低讀并發(fā)度
  • 公平策略:折中方案

典型使用場景

  • 配置信息的熱更新
  • 緩存系統(tǒng)
  • 高頻查詢低頻修改的數(shù)據(jù)結(jié)構(gòu)

8. 自旋鎖 (Spin Lock)

自旋鎖是一種非阻塞鎖,當線程無法獲取鎖時不會休眠,而是循環(huán)檢查鎖狀態(tài)(忙等待)。適用于鎖持有時間極短的場景。 

基本自旋鎖實現(xiàn)

#include <atomic>

class SpinLock {
    std::atomic_flag flag = ATOMIC_FLAG_INIT;
    
public:
    void lock() {
        while(flag.test_and_set(std::memory_order_acquire)) {
            // 可加入CPU暫停指令減少爭用時的能耗
            #ifdef __x86_64__
            __builtin_ia32_pause();
            #endif
        }
    }
    
    void unlock() {
        flag.clear(std::memory_order_release);
    }
    
    bool try_lock() {
        return !flag.test_and_set(std::memory_order_acquire);
    }
};

TTAS + Backoff

class AdvancedSpinLock {
    std::atomic<bool> locked{false};
    
public:
    void lock() {
        bool expected = false;
        int backoff = 1;
        const int max_backoff = 64;
        
        while(!locked.compare_exchange_weak(expected, true, 
              std::memory_order_acquire, std::memory_order_relaxed)) {
            expected = false; // compare_exchange_weak會修改expected
            
            // 指數(shù)退避
            for(int i = 0; i < backoff; ++i) {
                #ifdef __x86_64__
                __builtin_ia32_pause();
                #endif
            }
            
            backoff = std::min(backoff * 2, max_backoff);
        }
    }
    
    void unlock() {
        locked.store(false, std::memory_order_release);
    }
};

總結(jié)

以上為個人經(jīng)驗,希望能給大家一個參考,也希望大家多多支持腳本之家。

相關(guān)文章

  • C語言實現(xiàn)簡單五子棋游戲

    C語言實現(xiàn)簡單五子棋游戲

    這篇文章主要為大家詳細介紹了C語言實現(xiàn)簡單五子棋游戲,文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2021-11-11
  • 跨平臺C++包管理利器vcpkg的完全指南

    跨平臺C++包管理利器vcpkg的完全指南

    本文主要介紹了跨平臺C++包管理利器vcpkg的實現(xiàn),文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧
    2025-06-06
  • linux環(huán)境下C++實現(xiàn)俄羅斯方塊

    linux環(huán)境下C++實現(xiàn)俄羅斯方塊

    這篇文章主要為大家詳細介紹了linux環(huán)境下C++實現(xiàn)俄羅斯方塊,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2018-06-06
  • VC取得任務欄高度的方法

    VC取得任務欄高度的方法

    這篇文章主要介紹了VC取得任務欄高度的方法,需要的朋友可以參考下
    2014-07-07
  • C語言中printf()緩沖問題詳解

    C語言中printf()緩沖問題詳解

    這篇文章主要給大家介紹了關(guān)于C語言中printf()緩沖問題的相關(guān)資料,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧。
    2017-11-11
  • C/C++中的?Qt?StandardItemModel?數(shù)據(jù)模型應用解析

    C/C++中的?Qt?StandardItemModel?數(shù)據(jù)模型應用解析

    QStandardItemModel?是標準的以項數(shù)據(jù)為單位的基于M/V模型的一種標準數(shù)據(jù)管理方式,本文給大家介紹C/C++中的?Qt?StandardItemModel?數(shù)據(jù)模型應用解析,感興趣的朋友跟隨小編一起看看吧
    2021-12-12
  • ReSharper 的安裝使用詳細教程

    ReSharper 的安裝使用詳細教程

    resharper安裝教程是關(guān)于vs2012一個非常好用的插件的安裝教程,建議大家嘗試安裝,今天通過本教程幫助大家學習ReSharper 的安裝使用詳細教程,感興趣的朋友一起看看吧
    2021-06-06
  • C++實現(xiàn)控制臺隨機迷宮的示例代碼

    C++實現(xiàn)控制臺隨機迷宮的示例代碼

    本文主要介紹了C++實現(xiàn)控制臺隨機迷宮的示例代碼,文中通過示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2021-08-08
  • C++17中的std::optional的具體使用

    C++17中的std::optional的具體使用

    這篇文章主要介紹了C++17中的std::optional的具體使用,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧
    2021-01-01
  • VC枚舉串口端口應用

    VC枚舉串口端口應用

    這篇文章主要介紹了VC枚舉串口端口應用,羅列了常見的一些串口端口的應用實例,需要的朋友可以參考下
    2014-10-10

最新評論

安康市| 玛沁县| 绍兴市| 安国市| 高邮市| 航空| 牙克石市| 察隅县| 仪陇县| 广昌县| 大英县| 乐清市| 湖州市| 遂川县| 芷江| 桃园市| 安溪县| 察雅县| 阳新县| 北海市| 静宁县| 噶尔县| 平塘县| 萨嘎县| 汤阴县| 南康市| 永泰县| 鸡泽县| 扶余县| 宁海县| 宜黄县| 颍上县| 化隆| 封开县| 神池县| 保山市| 乐陵市| 剑阁县| 马公市| 启东市| 盐源县|