C++11 核心工具组件解析:std::mem_fn、std::chrono 与 std::this_thread

std::mem_fn:成员函数绑定
作用
- 将类的成员函数转换为可调用对象,使其可以像普通函数一样被调用。
- 适用于需要将成员函数作为回调或提交到线程池的场景。
原理
- std::mem_fn 生成一个函数对象,该对象接受一个指向类实例的指针(或引用)作为隐含参数,并调用对应的成员函数。
示例:
#include <functional>
#include <iostream>
class Dog {
public:
void bark() const {
std::cout << "Woof!" << std::endl;
}
};
int main() {
Dog dog;
auto bark_func = std::mem_fn(&Dog::bark);
bark_func(dog); // 输出 "Woof!"
return 0;
}
与 std::bind 的区别
- std::bind 可以绑定成员函数和对象实例,生成一个无参可调用对象:
auto bound_func = std::bind(&Dog::bark, &dog);
bound_func(); // 输出 "Woof!"
- std::mem_fn 生成的函数对象需要显式传递 this 指针:
auto mem_func = std::mem_fn(&Dog::bark);
mem_func(dog); // 必须传递 dog 对象
std::chrono
std::chrono
是 C++11 引入的时间处理库(定义于 <chrono>
头文件),提供了一套类型安全、高精度的时间操作框架,解决了传统 C 语言时间函数(如 time()
、clock()
)类型模糊、精度有限的问题。它通过时钟、时长和时间点三个核心概念,覆盖了从简单计时到复杂时间运算的全场景需求。
核心概念与组件
std::chrono
的设计基于三个核心组件,共同构成完整的时间模型:
1. 时钟(Clocks)
时钟是时间的“来源”,用于获取当前时间点,定义了时间的纪元(epoch,起始点)和精度。std::chrono
提供三种标准时钟:
时钟类型 | 特性 | 适用场景 |
---|---|---|
std::chrono::system_clock |
关联系统实时时间(可被用户或系统调整,如修改时区),纪元通常为 1970-01-01 UTC。 | 获取日历时间(年/月/日/时/分/秒) |
std::chrono::steady_clock |
时间单调递增(不受系统时间调整影响),精度通常高于 system_clock 。 |
测量时间间隔(如性能计时) |
std::chrono::high_resolution_clock |
高精度时钟,通常是 system_clock 或 steady_clock 的别名,提供尽可能高的精度。 |
对精度要求极高的计时场景 |
2. 时长(Durations)
时长表示两个时间点之间的间隔,定义为模板类 std::chrono::duration<Rep, Period>
,其中:
Rep
:存储时长的算术类型(如int
、long long
);Period
:时间单位,以秒为基准的分数(如std::ratio<1>
表示 1 秒,std::ratio<1, 1000>
表示 1 毫秒)。
标准预定义时长(简化使用):
using nanoseconds = duration<long long, std::nano>; // 纳秒(1e-9秒)
using microseconds = duration<long long, std::micro>; // 微秒(1e-6秒)
using milliseconds = duration<long long, std::milli>; // 毫秒(1e-3秒)
using seconds = duration<long long>; // 秒
using minutes = duration<int, std::ratio<60>>; // 分钟(60秒)
using hours = duration<int, std::ratio<3600>>; // 小时(3600秒)
基本操作:
// 定义时长
auto sec = std::chrono::seconds(5); // 5秒
auto ms = std::chrono::milliseconds(100); // 100毫秒
// 时长转换(需用 duration_cast 显式转换)
auto total_ms = std::chrono::duration_cast<std::chrono::milliseconds>(sec) + ms;
std::cout << total_ms.count() << "ms\n"; // 输出:5100ms(5秒=5000毫秒 + 100毫秒)
// 算术运算
auto half_min = std::chrono::minutes(1) / 2; // 30秒
3. 时间点(Time points)
时间点表示某一具体时刻,定义为模板类 std::chrono::time_point<Clock, Duration>
,其中:
Clock
:关联的时钟(如system_clock
),决定纪元;Duration
:时间点的精度(如milliseconds
)。
时间点的本质是“从时钟纪元开始的时长”,例如 system_clock
的时间点表示从 1970-01-01 00:00:00 到该时刻的秒数(或更高精度)。
基本操作:
// 获取当前时间点(基于系统时钟)
auto now = std::chrono::system_clock::now();
// 时间点与时长运算(得到新的时间点)
auto later = now + std::chrono::hours(2); // 当前时间 + 2小时
// 两个时间点相减(得到时长)
auto diff = later - now;
std::cout << std::chrono::duration_cast<std::chrono::minutes>(diff).count() << "分钟\n"; // 120分钟
常用功能示例
1. 测量代码执行时间(性能计时)
#include <chrono>
#include <iostream>
#include <thread>
int main() {
// 使用 steady_clock 计时(不受系统时间调整影响)
auto start = std::chrono::steady_clock::now();
// 模拟耗时操作(休眠500毫秒)
std::this_thread::sleep_for(std::chrono::milliseconds(500));
auto end = std::chrono::steady_clock::now();
// 计算耗时(转换为毫秒)
auto duration = std::chrono::duration_cast<std::chrono::milliseconds>(end - start);
std::cout << "耗时:" << duration.count() << "ms\n"; // 约500ms
return 0;
}
2. 时间点与日历时间的转换(system_clock
)
system_clock
可与传统 time_t
转换,用于格式化输出日历时间:
#include <ctime>
#include <iomanip>
int main() {
// 获取当前系统时间点
auto now = std::chrono::system_clock::now();
// 转换为 time_t(秒级精度)
std::time_t now_time_t = std::chrono::system_clock::to_time_t(now);
// 格式化输出(如:2024-05-20 15:30:45)
std::cout << "当前时间:" << std::put_time(std::localtime(&now_time_t), "%Y-%m-%d %H:%M:%S") << std::endl;
return 0;
}
3. 自定义时长单位
除标准时长外,可定义业务相关的时间单位(如“帧”“采样周期”等):
// 定义“帧”:假设1秒=60帧,1帧=1/60秒
using frame = std::chrono::duration<int, std::ratio<1, 60>>;
// 10帧的时长
frame f(10);
// 转换为毫秒(10/60秒 ≈ 166毫秒)
std::cout << "10帧 = " << std::chrono::duration_cast<std::chrono::milliseconds>(f).count() << "ms\n";
4. 线程休眠(结合 std::this_thread
)
std::chrono
时长可直接用于线程休眠,指定精确的阻塞时间:
// 休眠500毫秒
std::this_thread::sleep_for(std::chrono::milliseconds(500));
// 休眠至当前时间+2秒的时间点
std::this_thread::sleep_until(std::chrono::system_clock::now() + std::chrono::seconds(2));
与传统时间函数的对比
特性 | std::chrono |
传统 C 函数(time() 、clock() ) |
---|---|---|
类型安全 | 强类型,时长、时间点、时钟严格区分 | 弱类型,均用 time_t 或 clock_t 表示 |
精度 | 支持纳秒级高精度 | 通常为秒级或毫秒级 |
稳定性 | steady_clock 不受系统时间调整影响 |
受系统时间修改(如时区、夏令时)影响 |
易用性 | 支持算术运算(+、-)和单位转换 | 需手动计算和转换,易出错 |
注意事项
-
时钟选择:
- 计时、测量间隔优先用
steady_clock
(稳定、不受系统时间影响); - 获取日历时间(年月日)必须用
system_clock
。
- 计时、测量间隔优先用
-
单位转换:
低精度→高精度(如秒→毫秒)可无损转换,高精度→低精度(如毫秒→秒)可能丢失信息,需用duration_cast
显式转换(编译期检查)。 -
性能权衡:
高精度时钟(如high_resolution_clock
)的频繁调用可能带来性能开销,需平衡精度与效率。
总结
std::chrono
是现代 C++ 时间处理的标准方案,通过时钟、时长、时间点的清晰划分,提供了类型安全、高精度的时间操作能力。它不仅解决了传统时间函数的缺陷,还能轻松应对从简单计时到复杂时间运算的需求,尤其适合对时间精度和稳定性要求高的场景(如实时系统、性能测试、定时任务等)。
std::this_thread
std::this_thread
是 C++11 引入的线程操作命名空间(定义于 <thread>
头文件),提供了一组针对当前线程的操作函数,用于控制线程的行为(如休眠、获取线程 ID 等)。它是线程自我管理的核心工具,简化了线程控制的基本操作。
核心功能
std::this_thread
命名空间下的函数均作用于调用该函数的线程本身(即“当前线程”),主要用于线程休眠、身份标识等基础操作,无需依赖其他线程对象。
主要函数详解
1. std::this_thread::sleep_for
- 功能:使当前线程休眠指定的时长(阻塞状态),期间不占用 CPU 时间片。
- 原型:
template< class Rep, class Period > void sleep_for( const std::chrono::duration<Rep, Period>& duration );
- 参数:
duration
为休眠时长(需用std::chrono
库的时长类型,如milliseconds
、seconds
等)。 - 示例:
#include <thread> #include <chrono> #include <iostream> int main() { std::cout << "开始休眠..." << std::endl; // 休眠500毫秒 std::this_thread::sleep_for(std::chrono::milliseconds(500)); std::cout << "休眠结束" << std::endl; return 0; }
2. std::this_thread::sleep_until
- 功能:使当前线程休眠至指定的时间点(阻塞状态),到达该时间点后唤醒。
- 原型:
template< class Clock, class Duration > void sleep_until( const std::chrono::time_point<Clock, Duration>& timeout_time );
- 参数:
timeout_time
为唤醒的目标时间点(需用std::chrono
库的time_point
类型)。 - 示例:
// 休眠至当前时间点后2秒 auto wake_time = std::chrono::system_clock::now() + std::chrono::seconds(2); std::this_thread::sleep_until(wake_time); std::cout << "到达指定时间点,唤醒" << std::endl;
3. std::this_thread::yield
- 功能:当前线程主动放弃 CPU 时间片,允许操作系统调度其他线程运行(非阻塞,只是“谦让”)。
- 原型:
void yield() noexcept;
- 适用场景:在循环等待中减少 CPU 占用(如自旋锁的实现),避免线程长时间独占 CPU。
- 示例:
bool ready = false; // 共享标志位 // 线程1:等待ready变为true std::thread t1([&ready](){ while (!ready) { std::this_thread::yield(); // 主动让出CPU,减少空转消耗 } std::cout << "条件满足,退出等待" << std::endl; }); // 线程2:设置ready为true std::thread t2([&ready](){ std::this_thread::sleep_for(std::chrono::seconds(1)); ready = true; }); t1.join(); t2.join();
4. std::this_thread::get_id
- 功能:获取当前线程的唯一标识符(
std::thread::id
类型)。 - 原型:
std::thread::id get_id() noexcept;
- 用途:标识线程身份(如日志记录、调试、线程间区分)。
- 示例:
// 在主线程中获取ID std::cout << "主线程ID:" << std::this_thread::get_id() << std::endl; // 在子线程中获取ID std::thread t([](){ std::cout << "子线程ID:" << std::this_thread::get_id() << std::endl; }); t.join();
关键特性
- 仅作用于当前线程:所有函数均操作调用者自身线程,无需传递线程对象,使用简单。
- 与
std::chrono
深度集成:sleep_for
和sleep_until
直接接受std::chrono
库的时长和时间点,确保时间精度和类型安全。 - 无线程管理功能:
std::this_thread
不负责线程的创建、销毁、连接(join
)或分离(detach
),这些功能由std::thread
类提供。
与 std::thread
的区别
组件 | 功能范围 | 典型用法 |
---|---|---|
std::this_thread |
控制当前线程(休眠、让出CPU、获取ID) | sleep_for 、yield 、get_id |
std::thread |
管理线程生命周期(创建、销毁、连接、分离) | 线程对象构造、join() 、detach() 、get_id() |
注意事项
sleep_for
的实际休眠时间可能更长:由于操作系统调度机制,实际休眠时间可能略长于指定时长(但不会更短)。yield
不保证线程切换:yield
仅提示操作系统可以调度其他线程,但最终是否切换由操作系统决定(可能仍调度当前线程)。- 线程 ID 的唯一性:同一进程内的线程 ID 唯一,但不同进程的线程 ID 可能重复。
典型应用场景
- 延时操作:
sleep_for
用于简单的定时等待(如模拟网络延迟、定期轮询)。 - 定时任务:
sleep_until
用于精确到时间点的唤醒(如每天固定时间执行任务)。 - 减少 CPU 占用:
yield
用于循环等待场景(如自旋锁),避免线程空转消耗 CPU。 - 线程标识:
get_id
用于日志输出、调试信息或线程专属资源的绑定。
总结
std::this_thread
是线程自我控制的基础工具集,提供了休眠、让出 CPU、获取线程 ID 等核心操作,与 std::thread
配合使用可完成线程的全生命周期管理。它的接口简洁直观,尤其在结合 std::chrono
库后,能轻松实现高精度的线程时间控制,是多线程编程中不可或缺的组件。
更多推荐
所有评论(0)