C++11 std::chrono库详解

本文详细介绍了C++11及以后版本中的chrono库,它用于处理时间间隔、时钟和时间点。chrono库的核心包括duration、clocks和timepoints。duration类模板表示时间间隔,其单位可以使用std::ratio进行定义,如纳米、微秒、毫秒等。文章还列举了一些预定义的比率,并提供了chrono库在实际编程中的应用示例。

https://www.cnblogs.com/zlshmily/p/10058427.html

https://blog.youkuaiyun.com/albertsh/article/details/105468687?utm_medium=distribute.pc_relevant.none-task-blog-BlogCommendFromMachineLearnPai2-1.control&depth_1-utm_source=distribute.pc_relevant.none-task-blog-BlogCommendFromMachineLearnPai2-1.control

https://www.cnblogs.com/-citywall123/p/12623266.html

https://jingyan.baidu.com/article/63acb44aac1df421fcc17eff.html

https://blog.youkuaiyun.com/bladelyer/article/details/7180932

https://www.runoob.com/cprogramming/c-function-ctime.html

chrono 的概况
头文件 #include <chrono>
命名空间std::chrono
这个库从 C++11 引入标准之后,每个版本都有所修改,不过核心内容变化不是太大,他定义了三种主要类型,分别是 durationclockstime points,以及围绕这些类型的一些工具函数和衍生的定义。

chrono 的核心内容
duration
这个模板类用来表示时间间隔,我们知道时间的基本单位是秒,这个类的对象所表示的时间间隔也是以秒为单位的,它的定义如下:

template<class Rep, class Period = std::ratio<1>>
class duration;

Rep 表示一种数值类型,用来描述周期 Period 的数值类型,比如可以是 int、float 等,而 Period 的类型是std::ratio,同样是一个模板类,实际表示的是一个有理数,像100、0、1/1000(千分之一)等等。

在 std 这个命名空间下有很多已经定义好的有理数,可以举几个常见的头文件<ratio>中的例子:

nano    std::ratio<1, 1000000000>   // 十亿分之一
micro   std::ratio<1, 1000000>      // 百万分之一
milli   std::ratio<1, 1000>         // 千分之一
centi   std::ratio<1, 100>          // 百分之一
deci    std::ratio<1, 10>           // 十分之一
deca    std::ratio<10, 1>           // 十
hecto   std::ratio<100, 1>          // 百
kilo    std::ratio<1000, 1>         // 千

http://www.voidcn.com/article/p-hcmcjcum-bac.html

<think> 我们被要求介绍C++11std::thread的join()方法。根据引用内容,我们需要注意以下几点: 1. join()方法用于等待线程完成执行。 2. 调用join()之前必须检查线程是否可join(通过joinable()方法)。 3. 不可join的情况包括:默认构造的线程对象、已经被移动的线程对象、已经调用过join()或detach()的线程对象。 下面我们将详细解释join()方法,包括其作用、使用注意事项和示例代码。 ### 一、`std::thread::join()` 方法的作用 - 当调用 `join()` 时,当前线程(通常是主线程或调用者线程)会阻塞,直到被调用的线程执行完成。 - 一旦线程执行完毕,调用 `join()` 的线程会继续执行。 - 调用 `join()` 后,线程对象不再关联任何线程(即变成不可join的状态),并且可以安全销毁。 ### 二、使用 `join()` 的注意事项 1. **只能对可join的线程调用`join()`** 以下情况线程不可join(调用`join()`会抛出`std::system_error`异常): - 默认构造的`std::thread`对象(没有关联任何线程函数) - 线程已被移动(所有权转移) - 已经调用过`join()`或`detach()` 2. **必须检查`joinable()`** 在调用`join()`前务必检查: ```cpp std::thread t([]{ /* 任务 */ }); if (t.joinable()) { t.join(); } ``` 3. **避免遗漏`join()`导致程序终止** 如果线程对象在析构时仍可join(即未调用`join()`或`detach()`),则程序会调用`std::terminate()`终止。因此务必确保每个线程在销毁前被正确处理。 ### 三、代码示例 ```cpp #include <iostream> #include <thread> #include <chrono> void worker_task() { std::cout << "Worker thread started\n"; std::this_thread::sleep_for(std::chrono::seconds(2)); // 模拟耗时操作 std::cout << "Worker thread finished\n"; } int main() { // 创建并启动线程 std::thread t(worker_task); // 主线程继续执行其他任务 std::cout << "Main thread is waiting for worker...\n"; // 等待工作线程结束(阻塞) if (t.joinable()) { t.join(); // 正确:等待线程完成 } std::cout << "Main thread continues after join\n"; return 0; } ``` #### 输出结果: ``` Main thread is waiting for worker... Worker thread started Worker thread finished Main thread continues after join ``` ### 四、`join()` 与 `detach()` 的选择 - **`join()`**:需要等待线程结果时使用(同步) - **`detach()`**:让线程在后台运行(分离),调用后线程对象不再管理该线程(不可再join) ### 五、常见错误 1. **重复调用`join()`** ```cpp t.join(); t.join(); // 抛出std::system_error ``` 2. **忘记调用`join()`或`detach()`** ```cpp { std::thread t(worker_task); } // 作用域结束,t析构时仍可join -> 程序终止 ``` ### 六、最佳实践 - 使用RAII包装线程,确保自动释放: ```cpp class ThreadGuard { public: explicit ThreadGuard(std::thread& t) : t_(t) {} ~ThreadGuard() { if (t_.joinable()) { t_.join(); // 或根据需求选择detach() } } // 禁止复制 ThreadGuard(const ThreadGuard&) = delete; ThreadGuard& operator=(const ThreadGuard&) = delete; private: std::thread& t_; }; // 使用示例 std::thread t(worker_task); ThreadGuard guard(t); ``` §§相关问题§§ 1. `std::thread::detach()`的使用场景有哪些? 2. 如何处理多个线程的同步等待? 3. C++11中还有哪些线程管理机制? [^1]: 默认构造、已移动或已结束的线程对象不可join [^2]: 遗漏`join()`或`detach()`会导致程序终止 [^3]: 重复调用`join()`会抛出异常 </think> ### C++11 `std::thread::join()` 方法详解 #### 一、核心作用 `std::thread::join()` 是线程同步的关键方法,主要功能是: 1. **阻塞当前线程**(通常为主线程),直到目标线程执行完毕 2. **回收线程资源**,确保线程对象安全销毁 3. **同步线程生命周期**,防止线程访问已销毁的资源 ```cpp std::thread t([]{ std::cout << "Worker thread running\n"; }); t.join(); // 主线程在此阻塞,等待t结束 std::cout << "Main thread continues\n"; ``` #### 二、使用前提:`joinable()` 检查 调用 `join()` 前必须验证线程是否可连接,否则会抛出 `std::system_error` 异常: ```cpp if (t.joinable()) { // 必须检查! t.join(); } ``` ##### 不可 `join` 的三种情况: 1. **默认构造的线程对象**(未关联线程函数) ```cpp std::thread t1; // 默认构造 t1.joinable(); // 返回 false ``` 2. **已被移动的线程对象**(所有权转移) ```cpp std::thread t2(worker_func); std::thread t3 = std::move(t2); // t2 所有权转移 t2.joinable(); // 返回 false ``` 3. **已执行过 `join()` 或 `detach()`** ```cpp t3.join(); t3.joinable(); // 返回 false ``` #### 三、未正确处理的风险 若线程对象析构时仍可连接(未调用 `join()` 或 `detach()`),会触发 `std::terminate()` 导致程序终止: ```cpp { std::thread t(worker_func); } // 作用域结束,t 析构时仍 joinable -> 程序崩溃! ``` #### 四、与 `detach()` 的区别 | 方法 | 阻塞调用方 | 资源回收时机 | 线程控制权 | |-----------|------------|--------------------|------------| | `join()` | 是 | 调用时立即回收 | 保持关联 | | `detach()`| 否 | 线程结束时自动回收 | 放弃关联 | ```cpp std::thread t(background_task); t.detach(); // 主线程继续执行,不等待t ``` #### 五、典型应用场景 1. **等待结果返回** ```cpp int result; std::thread t([&]{ result = compute(); }); t.join(); std::cout << result; // 安全访问结果 ``` 2. **资源有序释放** ```cpp auto* res = new Resource(); std::thread t([res]{ use(res); delete res; // 在线程内释放 }); t.join(); ``` 3. **多阶段任务同步** ```cpp std::thread stage1(task1); stage1.join(); std::thread stage2(task2); // 确保 stage1 完成 ``` #### 六、最佳实践 1. **RAII 封装自动管理** ```cpp class ThreadGuard { public: explicit ThreadGuard(std::thread& t) : t_(t) {} ~ThreadGuard() { if(t_.joinable()) t_.join(); } // 禁止复制 private: std::thread& t_; }; std::thread t(task); ThreadGuard guard(t); // 析构时自动 join ``` 2. **避免主线程意外退出** ```cpp int main() { std::thread t(long_running_task); // ... 可能抛异常的代码 if (t.joinable()) t.join(); // 异常安全处理 } ``` > ⚠️ **关键原则**:每个 `std::thread` 对象在销毁前必须调用 `join()` 或 `detach()` 之一[^1][^3]。
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值