🍑个人主页:Jupiter.
🚀 所属专栏:C++学习笔记
欢迎大家点赞收藏评论😊

在这里插入图片描述

在这里插入图片描述


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_clocksteady_clock 的别名,提供尽可能高的精度。 对精度要求极高的计时场景
2. 时长(Durations)

时长表示两个时间点之间的间隔,定义为模板类 std::chrono::duration<Rep, Period>,其中:

  • Rep:存储时长的算术类型(如 intlong 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_tclock_t 表示
精度 支持纳秒级高精度 通常为秒级或毫秒级
稳定性 steady_clock 不受系统时间调整影响 受系统时间修改(如时区、夏令时)影响
易用性 支持算术运算(+、-)和单位转换 需手动计算和转换,易出错

注意事项

  1. 时钟选择

    • 计时、测量间隔优先用 steady_clock(稳定、不受系统时间影响);
    • 获取日历时间(年月日)必须用 system_clock
  2. 单位转换
    低精度→高精度(如秒→毫秒)可无损转换,高精度→低精度(如毫秒→秒)可能丢失信息,需用 duration_cast 显式转换(编译期检查)。

  3. 性能权衡
    高精度时钟(如 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 库的时长类型,如 millisecondsseconds 等)。
  • 示例
    #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_forsleep_until 直接接受 std::chrono 库的时长和时间点,确保时间精度和类型安全。
  • 无线程管理功能std::this_thread 不负责线程的创建、销毁、连接(join)或分离(detach),这些功能由 std::thread 类提供。

std::thread 的区别

组件 功能范围 典型用法
std::this_thread 控制当前线程(休眠、让出CPU、获取ID) sleep_foryieldget_id
std::thread 管理线程生命周期(创建、销毁、连接、分离) 线程对象构造、join()detach()get_id()

注意事项

  1. sleep_for 的实际休眠时间可能更长:由于操作系统调度机制,实际休眠时间可能略长于指定时长(但不会更短)。
  2. yield 不保证线程切换yield 仅提示操作系统可以调度其他线程,但最终是否切换由操作系统决定(可能仍调度当前线程)。
  3. 线程 ID 的唯一性:同一进程内的线程 ID 唯一,但不同进程的线程 ID 可能重复。

典型应用场景

  • 延时操作sleep_for 用于简单的定时等待(如模拟网络延迟、定期轮询)。
  • 定时任务sleep_until 用于精确到时间点的唤醒(如每天固定时间执行任务)。
  • 减少 CPU 占用yield 用于循环等待场景(如自旋锁),避免线程空转消耗 CPU。
  • 线程标识get_id 用于日志输出、调试信息或线程专属资源的绑定。

总结

std::this_thread 是线程自我控制的基础工具集,提供了休眠、让出 CPU、获取线程 ID 等核心操作,与 std::thread 配合使用可完成线程的全生命周期管理。它的接口简洁直观,尤其在结合 std::chrono 库后,能轻松实现高精度的线程时间控制,是多线程编程中不可或缺的组件。


Logo

汇聚全球AI编程工具,助力开发者即刻编程。

更多推荐