C++11&QT复习 (十九)

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<>> 放在堆上。

五、参考资源

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值