langShift

並發和多執行緒

並發和多執行緒對於建構高性能和響應式應用程式至關重要,尤其是在 C++ 中,可以直接控制執行緒。雖然 JavaScript 主要為單執行緒(非同步操作由事件循環處理),但 C++ 提供了強大的機制來實現真正的並行,允許同時運行多個任務。

多執行緒基本概念

  • 進程: 具有自己記憶體空間的獨立執行單元。
  • 執行緒: 進程內部的輕量級執行單元。同一進程內的執行緒共享相同的記憶體空間,這允許高效的資料共享,但也引入了競爭條件等挑戰。
  • 並發: 能夠同時執行多個任務(例如,透過在單一核心上快速切換任務)。
  • 並行: 能夠真正同時執行多個任務(例如,透過在不同的 CPU 核心上運行任務)。
  • 競爭條件: 多個執行緒同時存取和修改共享資料,最終結果取決於其執行不可預測的時序的情況。
  • 死鎖: 兩個或多個執行緒無限期地阻塞,等待彼此釋放資源的情況。

std::thread 用法

C++11 引入了 std::thread 用於建立和管理執行緒。它提供了一種簡單且可移植的方式來啟動新的執行流程。

正在加载...

互斥鎖和條件變數

當多個執行緒共享資料時,需要機制來防止競爭條件並確保資料完整性。

互斥鎖 (std::mutex)

  • 互斥鎖 (mutual exclusion) 是一種同步原語,用於保護共享資料免受多個執行緒的並發存取。一次只能有一個執行緒獲取互斥鎖。
  • lock() 獲取互斥鎖。如果已鎖定,呼叫執行緒將阻塞。
  • unlock() 釋放互斥鎖。
  • std::lock_guard / std::unique_lock 互斥鎖的 RAII 包裝器,確保它們在超出作用域時自動解鎖,即使發生例外。
正在加载...

條件變數 (std::condition_variable)

  • 條件變數用於根據特定條件同步執行緒。它們允許執行緒等待直到條件變為真,並在條件改變時收到通知。
  • 通常與互斥鎖一起使用,以保護條件所依賴的共享資料。

原子操作 (std::atomic)

原子操作是保證完全且不可分割地執行的操作,即使在多個執行緒存在的情況下也是如此。它們對於簡單的單變數更新很有用,在這種情況下,互斥鎖可能過於繁重。

  • std::atomic<int>:為整數提供原子操作。
  • fetch_addcompare_exchange_weak 等操作是原子的。
正在加载...

非同步程式設計 (async/await)

雖然 C++ 具有傳統的多執行緒,但現代 C++(C++11 起)也提供了促進非同步程式設計的功能,類似於 JavaScript 的 async/await

  • std::futurestd::promise 用於從非同步操作獲取結果。
  • std::async 啟動非同步任務並返回一個 std::future,該 std::future 最終將保存結果。
  • 協程 (C++20): 用於編寫看起來同步的非同步程式碼的更高級功能。
正在加载...

執行緒池設計

執行緒池是預先初始化執行緒的集合,可用於執行任務。任務不是為每個任務建立一個新執行緒,而是提交到執行緒池,由可用的執行緒拾取並執行任務。這減少了執行緒建立和銷毀的開銷,提高了具有許多短生命週期任務的應用程式的性能。

優點:

  • 減少執行緒建立/銷毀的開銷。
  • 管理活動執行緒的數量,防止資源耗盡。
  • 提高響應性。

與 JavaScript 非同步程式設計的比較

JavaScript 的並發模型基於單執行緒事件循環。雖然它可以處理許多操作並發(例如,網路請求、計時器)而不會阻塞主執行緒,但它透過非同步回呼、Promise 和 async/await 實現了這一點,而不是真正的並行。

特性JavaScript (事件循環、Async/Await)C++ (多執行緒、Async/Future)
並發透過非阻塞 I/O 和事件循環實現透過多個執行緒實現真正的並行
共享記憶體有限 (Web Workers 透過訊息傳遞,SharedArrayBuffer 透過 Atomics)直接共享記憶體存取 (需要同步)
同步透過事件循環隱式,SharedArrayBuffer 明確明確 (互斥鎖、條件變數、原子操作)
複雜性對於基本非同步任務更簡單由於明確的執行緒管理和同步而更複雜
用例UI 響應性、I/O 密集型任務CPU 密集型任務、高性能計算、即時系統

C++ 提供了對執行緒和記憶體進行精細控制的工具,實現真正的並行和計算密集型任務的最大性能。然而,這種能力伴隨著管理同步和避免常見並發陷阱的責任。


練習題:

  1. 解釋並發和並行之間的區別。C++ 如何實現並行,JavaScript 如何實現並發?
  2. 什麼是競爭條件,互斥鎖如何幫助在 C++ 中防止它?提供一個簡單的 C++ 程式碼範例,演示 std::mutex 的使用。
  3. 描述 C++ 中 std::asyncstd::future 的用途。它們如何促進非同步程式設計,這與 JavaScript 的 async/await 如何比較?

專案構想:

  • 在 C++ 中實作一個簡單的多執行緒質數計算器。將要檢查的數字範圍分配給多個執行緒。使用 std::thread 建立執行緒,並使用 std::mutexstd::atomic 安全地收集每個執行緒找到的質數。將其執行時間與單執行緒版本進行比較。