- 操作系统:ubuntu22.04
- IDE:Visual Studio Code
- 编程语言:C++11
算法描述
这两个函数都定义在 头文件中,属于 std::this_thread 命名空间,用于让当前线程暂停执行一段时间。
函数 | 功能 |
---|---|
sleep_for(rel_time) | 让当前线程休眠一段相对时间(例如:休眠 100 毫秒) |
sleep_until(abs_time) | 让当前线程休眠到某个绝对时间点(例如:休眠到 2025年9月15日中午12:00) |
函数原型
#include <thread>
#include <chrono>// 1. 休眠一段相对时间
template <class Rep, class Period>
void std::this_thread::sleep_for(const std::chrono::duration<Rep, Period>& rel_time);// 2. 休眠到某个绝对时间点
template <class Clock, class Duration>
void std::this_thread::sleep_until(const std::chrono::time_point<Clock, Duration>& abs_time);
⚠️ 注意:如果传入负的 rel_time,sleep_for 的行为等同于不休眠(立即返回)。
sleep_for 详解:休眠一段相对时间
✅ 语法示例:
using namespace std::chrono;// 休眠 100 毫秒
std::this_thread::sleep_for(100ms);// 或者写成:
std::this_thread::sleep_for(milliseconds(100));
std::this_thread::sleep_for(seconds(1)); // 休眠 1 秒
std::this_thread::sleep_for(microseconds(500)); // 500 微秒
🧠 工作原理:
- 当前线程调用 sleep_for 后,会进入阻塞状态(blocked)。
- 操作系统将其从 CPU 调度队列中移除。
- 经过指定时间后,操作系统将线程重新放入就绪队列,等待调度执行。
- 线程恢复执行。
⚠️ 注意事项:
-
实际休眠时间 ≥ 指定时间
因为操作系统调度不是实时的,sleep_for 只保证“至少休眠这么长时间”,但可能更长(尤其在系统负载高时)。 -
精度取决于系统和时钟
通常系统时钟精度为 1~15 毫秒,所以 sleep_for(1us) 可能实际休眠 1ms。 -
可被中断吗?
在标准 C++ 中,不能被信号或外部事件中断(不像 POSIX 的 sleep())。一旦调用,必须等到时间结束。
使用场景
场景1:控制循环频率(如游戏主循环、传感器采样)
while (running)
{read_sensor();process_data();std::this_thread::sleep_for(10ms); // 控制每 10ms 执行一次
}
场景2:重试机制中的退避策略(Retry with Backoff)
for (int i = 0; i < 3; ++i)
{if (try_connect()) break;std::this_thread::sleep_for(std::chrono::milliseconds(100 * (i + 1))); // 递增等待
}
sleep_until 详解:休眠到某个绝对时间点
✅ 语法示例:
using namespace std::chrono;// 获取当前时间 + 2 秒
auto now = system_clock::now();
auto two_seconds_later = now + seconds(2);
std::this_thread::sleep_until(two_seconds_later);// 或者指定一个具体时间点(比如明天上午 9:00)
auto tomorrow = system_clock::now() + hours(24);
auto nine_am = std::chrono::time_point_cast<hours>(tomorrow);
nine_am += hours(9); // 假设今天是 0 点,加 9 小时
std::this_thread::sleep_until(nine_am);
🧠 工作原理:
- sleep_until 接收一个 time_point 类型的时间点。
- 线程会一直阻塞,直到系统时钟达到或超过该时间点。
- 如果当前时间已经晚于或等于目标时间点,则 sleep_until 立即返回,不休眠。
✅ 使用场景
场景1:定时任务(如每天凌晨执行)
void run_daily_task_at_midnight()
{while (true) {auto now = system_clock::now();auto tomorrow = system_clock::from_time_t(std::chrono::system_clock::to_time_t(now) + 86400); // 明天 00:00:00auto midnight = std::chrono::time_point_cast<seconds>(tomorrow);std::this_thread::sleep_until(midnight);perform_daily_backup();}
}
场景2:多个线程同步到同一时间点启动
auto start_time = std::chrono::system_clock::now() + std::chrono::seconds(5);// 所有线程都调用:
std::this_thread::sleep_until(start_time);
// 从而实现“5秒后同时开始”
💡 这比每个线程自己计算 sleep_for(5s) 更精确,避免了启动延迟累积误差。
sleep_for vs sleep_until 对比
特性 | sleep_for | sleep_until |
---|---|---|
时间类型 | duration(持续时间) | time_point(时间点) |
语义 | “我要睡 5 秒” | “我要睡到明天 9:00” |
是否受系统时间调整影响 | 否 | 是(如果系统时间被修改) |
适合场景 | 延迟、重试、节流 | 定时任务、时间同步 |
若目标时间已过 | 休眠指定时间 | 立即返回(不休眠) |
⚠️ 注意:sleep_until 使用的是 system_clock,如果用户手动调整了系统时间,可能导致线程提前唤醒或延迟唤醒。
如果需要更稳定的时钟,可使用 steady_clock(见下文)。
推荐使用 steady_clock 避免系统时间跳变
虽然 system_clock 是最常用的时钟,但它受系统时间调整(如 NTP 同步、手动修改)影响。
对于延迟控制类任务,建议使用 steady_clock,它是单调递增的,不会倒退。
示例:使用 steady_clock 的 sleep_until
auto start = std::chrono::steady_clock::now();
auto deadline = start + std::chrono::milliseconds(100);std::this_thread::sleep_until(deadline); // 推荐用于定时延迟
steady_clock 不受系统时间修改影响,更适合做超时、延迟等操作。
常见误区与注意事项
❌ 误区1:sleep_for(1ms) 一定能精确休眠 1ms
→ 错!受操作系统调度精度限制,实际可能休眠 1~15ms。
❌ 误区2:sleep_until 绝对可靠
→ 如果系统时间被手动调整或 NTP 校正,system_clock 时间点可能跳变,导致提前或延迟唤醒。
❌ 误区3:可以在任意线程调用
→ 可以,但注意:主线程调用也会阻塞整个程序。
✅ 最佳实践:
延迟控制 → 优先用 sleep_for + steady_clock
定时任务 → 用 sleep_until + system_clock
高精度需求 → 考虑使用平台特定 API(如 nanosleep on Linux)
完整示例代码
#include <iostream>
#include <thread>
#include <chrono>int main()
{using namespace std::chrono;std::cout << "Start: " << system_clock::now().time_since_epoch().count() << std::endl;// 1. sleep_for:休眠 2 秒std::cout << "Sleeping for 2s..." << std::endl;std::this_thread::sleep_for(seconds(2));// 2. sleep_until:休眠到 3 秒后auto target = steady_clock::now() + milliseconds(1500);std::cout << "Sleeping until steady time point..." << std::endl;std::this_thread::sleep_until(target);std::cout << "Done!" << std::endl;return 0;
}
总结
函数 | 用途 | 推荐时钟 | 注意事项 |
---|---|---|---|
sleep_for(duration) | 休眠一段相对时间 | steady_clock | 保证最小休眠时间 |
sleep_until(time_point) | 休眠到某个绝对时间 | system_clock | 受系统时间调整影响 |
✅ 一句话总结:
用 sleep_for 控制“延迟多久”,
用 sleep_until 控制“什么时候开始”。
它们是多线程中实现节流、重试、定时、同步启动等行为的基础工具,理解其差异和适用场景,能让你写出更健壮的并发程序。