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

C++多線程與鎖機(jī)制使用解讀

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

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)建并啟動(dò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() - 分離線程,線程獨(dú)立運(yùn)行
// t.detach();

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

1.4 獲取當(dāng)前線程信息

#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 (自動(dòng)管理鎖)

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

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

2.2 unique_lock

unique_lock 比 lock_guard 更靈活,可以手動(dòng)上鎖和解鎖。

void increment_flexible() {
    for (int i = 0; i < 100000; ++i) {
        std::unique_lock<std::mutex> lock(mtx);
        ++shared_data;
        lock.unlock(); // 可以手動(dòng)解鎖
        // 做一些不需要鎖的操作
        lock.lock();   // 再手動(dòng)上鎖
        ++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 定時(shí)互斥鎖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 {
        // 超時(shí)未能獲取鎖
        std::cout << "Could not get the lock within 100ms\n";
    }
}

2.6std::adopt_lock與std::defer_lock

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

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

#include <mutex>

std::mutex mtx;

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

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); // 無(wú)條件等待,可能虛假喚醒

 帶謂詞的 wait()

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

wait_for() - 帶超時(shí)等待

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

wait_until() - 等待到指定時(shí)間點(diǎn)

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

3.2notify

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

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

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

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

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

#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)

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

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

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

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

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;       // 默認(rèn)初始化為0

4.2 加載和存儲(chǔ)

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

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

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更新為當(dāng)前value,返回false

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

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

// 默認(rèn)是最嚴(yán)格的內(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: 無(wú)順序保證
// - memory_order_consume: 數(shù)據(jù)依賴順序
// - memory_order_acquire: 讀操作,防止上方讀寫重排
// - memory_order_release: 寫操作,防止下方讀寫重排
// - memory_order_acq_rel: 讀-修改-寫操作
// - memory_order_seq_cst: 順序一致性 (默認(rèn))

4.7 原子標(biāo)志

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

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

// 清除標(biāo)志
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}};

// 必須是可平凡復(fù)制的類型(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 對(duì)模板類型 T 的關(guān)鍵要求是:

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

static_assert 在編譯時(shí)驗(yàn)證這些條件,若不滿足會(huì)立即報(bào)錯(cuò)(比運(yùn)行時(shí)錯(cuò)誤更安全)。

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

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

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

5. 死鎖預(yù)防

當(dāng)多個(gè)線程需要多個(gè)鎖時(shí),可能產(chǎn)生死鎖。

預(yù)防方法:

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

void safe_lock() {
    // 同時(shí)鎖定兩個(gè)互斥量,避免死鎖
    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. 線程局部存儲(chǔ) (thread_local)

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

#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. 讀寫鎖

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

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);
    }
    
    // 寫操作 - 使用獨(dú)占鎖
    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):多個(gè)線程可同時(shí)持有
  • 獨(dú)占寫鎖 (unique_lock):只有一個(gè)線程可持有
  • 升級(jí)鎖 (C++14沒有直接支持,需手動(dòng)實(shí)現(xiàn))

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

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

典型使用場(chǎng)景

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

8. 自旋鎖 (Spin Lock)

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

基本自旋鎖實(shí)現(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暫停指令減少爭(zhēng)用時(shí)的能耗
            #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會(huì)修改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é)

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

相關(guān)文章

  • C語(yǔ)言實(shí)現(xiàn)簡(jiǎn)單五子棋游戲

    C語(yǔ)言實(shí)現(xiàn)簡(jiǎn)單五子棋游戲

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

    跨平臺(tái)C++包管理利器vcpkg的完全指南

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

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

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

    VC取得任務(wù)欄高度的方法

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

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

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

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

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

    ReSharper 的安裝使用詳細(xì)教程

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

    C++實(shí)現(xiàn)控制臺(tái)隨機(jī)迷宮的示例代碼

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

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

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

    VC枚舉串口端口應(yīng)用

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

最新評(píng)論

浑源县| 湾仔区| 沁阳市| 眉山市| 娄底市| 达州市| 孟津县| 井冈山市| 台北县| 合阳县| 焉耆| 五台县| 新昌县| 宣化县| 和政县| 东明县| 民和| 广河县| 古丈县| 岳普湖县| 左贡县| 抚州市| 郁南县| 沾益县| 江永县| 临夏县| 紫金县| 衡山县| 苗栗县| 德惠市| 北安市| 兴山县| 和平县| 诸城市| 无棣县| 虎林市| 遂昌县| 溧水县| 商洛市| 儋州市| 南昌县|