第 18.19 節

併發編程

0瀏覽次數0訪問次數--跳出率--平均停留

本節解決什麼問題

現代計算機通常有多個 CPU 核心。一個程序如果只在一個線程裏順序執行,就無法讓多個耗時任務同時推進。典型場景包括:

  • 一個線程保持界面響應,另一個線程處理後台任務。
  • 同時等待多個網絡請求、定時器或外設事件。
  • 把可拆分的計算任務分給多個線程。

併發編程的難點不在於"開線程"本身,而在於生命週期和共享數據。只要兩個線程同時讀寫同一份數據,就必須認真處理同步問題。

學習路線

本節拆成幾個文件級子章節來學:

  • std::thread:創建線程,並用 join() 等待結束。
  • std::mutexstd::lock_guard:保護共享數據。
  • std::atomic:簡單計數器的無鎖線程安全操作。
  • std::condition_variable:一個線程等待另一個線程發通知。

如果只啓動一個任務,同步和併發的結果可能看起來一樣。差異通常要在"兩個或更多任務同時等待或同時計算"時才明顯。這和 Boost.Asio 中一個定時器看不出異步優勢、兩個定時器才看出區別是同一個道理。

C++ 標準版本

C++11 引入了標準線程庫。C++14、C++17、C++20 又增加了 std::shared_mutexstd::jthreadstd::latchstd::barrier 等工具。

本節主要使用 C++11 就有的基礎工具。編譯時通常需要加線程選項,例如:

g++ demo.cpp -std=c++17 -pthread

常用工具

工具作用常見頭文件
std::thread創建和管理線程<thread>
std::this_thread::sleep_for當前線程休眠一段時間<thread><chrono>
std::mutex互斥鎖,保護共享數據<mutex>
std::lock_guardRAII 加鎖,作用域結束自動解鎖<mutex>
std::unique_lock更靈活的 RAII 鎖,常配合條件變量<mutex>
std::atomic原子變量,適合簡單計數<atomic>
std::condition_variable等待和通知<condition_variable>

併發和並行

概念含義例子
併發多個任務在同一段時間內推進一個程序同時等待網絡、定時器和用户輸入
並行多個任務真的同時運行多核 CPU 上多個線程同時計算

初學時先抓住工程直覺:多個任務都要等待外設、網絡、定時器或耗時計算時,讓它們同時推進,程序整體會更快或響應更好。

使用建議

  1. 先保證正確,再考慮性能。
  2. 能不共享數據就不共享數據,每個線程處理自己的數據最簡單。
  3. 共享數據優先用 mutex 保護,簡單計數才考慮 atomic
  4. 鎖的作用域儘量小,避免長時間持鎖。
  5. 初學階段少用 detach(),優先用 join() 明確等待線程結束。
  6. C++20 項目可以瞭解 std::jthread,它析構時會自動請求停止並 join,比 std::thread 更安全。

工程拓展

在 ROS2 中,多線程回調執行器、回調組和共享狀態保護都會涉及線程與鎖。在 Boost.Asio 中,多個異步任務可能運行在同一個 io_context 或線程池裏,也要考慮回調之間的共享數據。學好 C++ 標準庫併發工具,再看這些工程庫會輕鬆很多。

音乐页