文章目录
- 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 (书籍)