首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> C語言 >> C++ >> 關於C++

C++11 多線程編程實戰:從 atomic 到 condition_variable 完整指南

     編輯:關於C++

一、原子操作 <atomic>

原子操作是多線程中「最小且不可並行化」的操作,C++11 在 <atomic> 提供跨平台支援,底層映射至 CPU 原子指令(如 x86 的 lock 前綴)。

基本類型與用法

#include 
#include 
#include 
using namespace std;

atomic total{0}; // C++11 列表初始化

void func(int) {
    for (long long i = 0; i < 100'000'000; ++i)
        total += i; // 原子累加
}

int main() {
    thread t1(func, 0), t2(func, 0);
    t1.join(); t2.join();
    cout << total << endl; // 確定性結果
}

關鍵特性

  • std::atomic<T> 不可拷貝、不可移動,僅能從 T 構造,防止意外共享。
  • 讀寫對應 load() / store(),支援 memory_order 微調一致性模型。
  • 複合操作:fetch_add、compare_exchange_weak/strong 等實現無鎖演算法。

二、線程管理 <thread>

建立與同步

void task(int id) { /* ... */ }

int main() {
    thread t1(task, 1);           // 直接傳參
    thread t2([](int n){ /* ... */}, 2); // Lambda
    thread t3(bind(task, 3));     // std::bind

    t1.join();  // 阻塞等待結束
    t2.detach(); // 分離,主線程不再管理,需確保線程安全退出
}
  • join():阻塞調用者直到線程結束,確保資源釋放。
  • detach():線程與 thread 對象分離,獨立運行,對象析構不影響線程,但無法再 join。
  • thread 不可拷貝,可移動(std::move)。

三、互斥量與鎖 <mutex>

四種互斥量

類型特性適用場景
mutex獨占、非遞歸通用臨界區保護
recursive_mutex同一線程可重複鎖定遞歸算法、複雜重入(慎用)
timed_mutex支援 try_lock_for/until需超時控制的鎖獲取
recursive_timed_mutex遞歸 + 超時罕見,極度複雜同步

RAII 鎖包裝器:首選 lock_guard / unique_lock

mutex mtx;

void safe_func() {
    lock_guard guard(mtx); // 構造加鎖,析構解鎖,防忘解鎖
    // 臨界區
}

void flexible_func() {
    unique_lock ul(mtx);   // 可手動 unlock/lock,支援條件變量
    ul.unlock();                  // 提前釋放
    // 非臨界區代碼
    ul.lock();                    // 重新加鎖
}

四、條件變量 <condition_variable>

條件變量實現「等待-通知」模式,必須搭配 unique_lock<mutex> 使用。

核心 API

函數說明
wait(lock)釋放鎖並阻塞,被喚醒後重新獲取鎖
wait_for(lock, duration)超時等待,返回 cv_status
wait_until(lock, time_point)截止時間等待
notify_one()喚醒一個等待線程
notify_all()喚醒所有等待線程

經典生產者-消費者模式

mutex mtx;
condition_variable cv;
bool ready = false;

void worker(int id) {
    unique_lock lck(mtx);
    while (!ready) cv.wait(lck); // 必須用 while 防虛假喚醒
    cout << "Thread " << id << " running\n";
}

void go() {
    {
        unique_lock lck(mtx);
        ready = true;
    }
    cv.notify_all(); // 在鎖外通知,減少競爭
}

int main() {
    thread threads[10];
    for (int i = 0; i < 10; ++i) threads[i] = thread(worker, i);
    go();
    for (auto& t : threads) t.join();
}

關鍵點總結

  1. 條件變量 不保存狀態,需配合 bool ready 等標誌位。
  2. wait 內部自動 unlock -> sleep -> relock,原子性保證。
  3. 必須用 while (!condition) 而非 if,防禦虛假喚醒。
  4. notify_all 在鎖外調用可減少鎖競爭(推薦做法)。
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved