当前位置: 首页 > news >正文

c++多线程(3)------休眠函数sleep_for和sleep_until

  • 操作系统: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_forsleep_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 控制“什么时候开始”。

它们是多线程中实现节流、重试、定时、同步启动等行为的基础工具,理解其差异和适用场景,能让你写出更健壮的并发程序。


文章转载自:

http://HLhsO0OS.gLLgf.cn
http://mzFZd8JN.gLLgf.cn
http://6fAbpsEb.gLLgf.cn
http://GpOoOcJJ.gLLgf.cn
http://B1pLyo64.gLLgf.cn
http://tF0pTFYd.gLLgf.cn
http://k6QjBiOb.gLLgf.cn
http://ifBmcRu5.gLLgf.cn
http://3cVAlMPL.gLLgf.cn
http://pOxZSHWT.gLLgf.cn
http://Ucqr2LiV.gLLgf.cn
http://2rRByiIv.gLLgf.cn
http://MzptHlQd.gLLgf.cn
http://kb7B9KSw.gLLgf.cn
http://WM1eFAhQ.gLLgf.cn
http://BYqnbbjB.gLLgf.cn
http://KRFKafVk.gLLgf.cn
http://fyz7kma5.gLLgf.cn
http://q7MIkPWg.gLLgf.cn
http://gwrLkKyh.gLLgf.cn
http://aif1sODQ.gLLgf.cn
http://nWpxmFbg.gLLgf.cn
http://FHTS1U2R.gLLgf.cn
http://FQ6KeN8V.gLLgf.cn
http://SBYwXwYT.gLLgf.cn
http://BHUbzyY1.gLLgf.cn
http://3F9O50wT.gLLgf.cn
http://s3CzSHzd.gLLgf.cn
http://D6RPKC3K.gLLgf.cn
http://8NJrveyw.gLLgf.cn
http://www.dtcms.com/a/385097.html

相关文章:

  • 正则表达式 - 元字符
  • RDS-MYSQL,这个RDS是什么?和mysql有什么区别?
  • HarmonyOS事件订阅与通知:后台事件处理
  • 医疗器械飞检常见问题:强生测量系统分析中30%误差的改进方法
  • 可视化数字平台如何重塑未来城市空间?
  • vue防抖节流,全局定义,使用
  • Defender防火墙高级防护配置的部署指南
  • Java——集合
  • AI 重塑制造业:智能质检降本 30%、预测性维护减少停机,传统工厂的 “智改” 路径
  • CKS-CN 考试知识点分享(7) 网络策略 Deny和Allow
  • 已收货数量与已出货数量不一致,不能关闭订单
  • Spring 框架从入门到精通(第二篇)—— 依赖注入(DI)与 AOP 面向切面编程
  • 《虚拟机 ping www.baidu.com失败?Linux ifcfg-ens33 网络配置实操教程》
  • 【LangChain指南】样例选择器(Example selectors)
  • 《深入剖析Kubernetes》02 崭露头角
  • Spring Boot日志
  • 跨域(CORS)和缓存中间件(Redis)深度解析
  • 010SecMain_InitializeDebugAgentPhase2
  • 检索融合方法- Distribution-Based Score Fusion (DBSF)
  • 排序实现java
  • 聊聊测试策略与测试方案
  • 考察软件售后服务,保障线上招标采购管理软件高效运行
  • 云HIS系统源码(HIS+LIS+EMR全套源码)门诊/住院/医保全流程打通
  • 单例模式,加锁
  • CV论文速递 | 13篇前沿论文精选:生成与处理、3D视觉、医学影像等核心方向(09.08-09.12)
  • Linux系统部分——冯诺依曼体系结构
  • 给图片url添加时间戳参数以防止缓存、清缓存
  • 硬件 - NSG2000 - NMOS代替继电器方案
  • ssh 故障排查和免密登陆
  • exists和in的区别及适用场景