文章目錄
- Day13 C++ 時間庫和線程庫學習筆記(Chrono 與 Thread)
- 一、時間庫 `<chrono>`
- 1.1 基本概念
- 1.2 使用示例
- 1.3 duration 字面量單位
- 二、線程庫 `<thread>`
- 2.1 基本用法
- 2.2 數據競爭(Race Condition)
- 2.3 加鎖:互斥鎖 `std::mutex`
- 2.4 示例:單線程與多線程性能對比
- 單線程版本
- 多線程 + 共享內存(未加鎖)
- 多線程 + 加鎖
- 優化版:每線程局部求和后再加總(鎖移出循環)
- 三、線程安全總結
- 四、調試建議
- 五、參考資源
Day13 C++ 時間庫和線程庫學習筆記(Chrono 與 Thread)
一、時間庫 <chrono>
1.1 基本概念
C++ 的 <chrono>
時間庫中包含三個核心概念:
- Clock(時鐘):提供當前時間的來源,常用的有:
system_clock
:系統時間,可轉換為time_t
類型(適合打印日志)steady_clock
:單調時鐘,適合測量時間間隔(不受系統時間修改影響)high_resolution_clock
:高精度時鐘,底層通常等同于steady_clock
- time_point(時間點):代表某個時鐘上的具體時刻。
- duration(時間段):表示兩個時間點之間的時間差。
1.2 使用示例
#include <chrono>
#include <iostream>
#include <ctime>
#include <thread>void wait_or_sleep_for_or_until() {using namespace std::chrono_literals; // 支持 1s, 10ms 等單位std::this_thread::sleep_for(1s); // 睡眠1秒(使用 duration 類型)std::this_thread::sleep_until(std::chrono::high_resolution_clock::now() + 1s); // 睡眠到某時間點
}void calculate_execution_time() {auto before = std::chrono::high_resolution_clock::now();// 執行某段代碼auto after = std::chrono::high_resolution_clock::now();auto elapsed = std::chrono::duration_cast<std::chrono::milliseconds>(after - before);std::cout << "Elapsed: " << elapsed.count() << " ms\n";
}int main() {auto now = std::chrono::system_clock::now();std::time_t now_c = std::chrono::system_clock::to_time_t(now);std::cout << "Current time: " << std::ctime(&now_c);
}
1.3 duration 字面量單位
使用 std::chrono_literals
命名空間后支持:
h
,min
,s
,ms
,us
,ns
二、線程庫 <thread>
2.1 基本用法
創建線程的方式:
std::thread t(func); // 執行 func()
t.join(); // 等待線程結束
t.detach(); // 讓線程獨立運行,主線程不再等待
線程函數可以使用 lambda 表達式,支持傳入引用:
int x = 10;
std::thread t([&x] { x += 5; });
t.join();
2.2 數據競爭(Race Condition)
多個線程同時修改共享變量(如 sum
)會引發數據競爭,結果不確定。
2.3 加鎖:互斥鎖 std::mutex
std::mutex mtx;
mtx.lock();
sum += value;
mtx.unlock();
推薦使用 std::lock_guard
實現 RAII 風格的自動加鎖解鎖:
std::lock_guard<std::mutex> lock(mtx);
sum += value; // 自動解鎖
2.4 示例:單線程與多線程性能對比
單線程版本
void single_thread() {auto data = generate_data();unsigned long long sum = 0;Timer clock;for (const auto& array : data) {for (int i : array) {// 計算密集操作(模擬)sum += i;}}std::cout << "single_thread: " << clock.duration() << " sum: " << sum << "\n";
}
多線程 + 共享內存(未加鎖)
void race_condition_of_shared_memory() {unsigned long long sum = 0;std::vector<std::thread> threads;for (const auto& array : data) {threads.emplace_back([&] {for (int i : array) sum += i; // 存在數據競爭!});}for (auto& t : threads) t.join();
}
多線程 + 加鎖
void mutex_version() {std::mutex mtx;unsigned long long sum = 0;for (...) {threads.emplace_back([&] {for (...) {std::lock_guard<std::mutex> lock(mtx);sum += i;}});}
}
優化版:每線程局部求和后再加總(鎖移出循環)
void mutex_out_of_loop() {std::mutex mtx;unsigned long long sum = 0;for (...) {threads.emplace_back([&] {unsigned long long local_sum = 0;for (...) local_sum += i;std::lock_guard<std::mutex> lock(mtx);sum += local_sum;});}
}
三、線程安全總結
方案 | 是否安全 | 性能 | 說明 |
---|---|---|---|
單線程 | 安全 | 慢 | 無并發 |
多線程(無加鎖) | 不安全 | 快但錯誤 | 數據競爭 |
多線程 + 每次加鎖 | 安全 | 慢 | 鎖粒度太小 |
多線程 + 聚合后加鎖 | 安全 | 快 | 推薦方案,鎖粒度大、代價低 |
四、調試建議
- 建議使用 Debug 模式運行,避免 release 模式優化導致時間測不準。
- 保持線程 join/detach 的正確性,避免程序異常終止。
- 避免棧內存分配超大數組,可使用
std::vector<std::array<>>
放在堆上。
五、參考資源
- zhihu chrono 詳解
- C++ Concurrency In Action (書籍)