• 操作系统: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://www.pswp.cn/bicheng/97028.shtml
繁体地址,请注明出处:http://hk.pswp.cn/bicheng/97028.shtml
英文地址,请注明出处:http://en.pswp.cn/bicheng/97028.shtml

如若内容造成侵权/违法违规/事实不符,请联系英文站点网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Intel RealSense D455深度相机驱动安装与运行

Intel RealSense D455深度相机安装过程遇到过一些报错&#xff0c;所以记录一下安装过程&#xff01;&#xff01;&#xff01;以后方便回顾。 1.安装最新的IntelRealSense SDK2.0 (1) 注册服务器的公钥 sudo apt-get update && sudo apt-get upgrade && su…

从异步到半同步:全面解读MySQL复制的数据一致性保障方案

MySQL 主从复制&#xff08;Replication&#xff09;是其最核心的高可用性和扩展性功能之一。它的原理是将一个 MySQL 实例&#xff08;称为主库 Master&#xff09;的数据变更&#xff0c;自动同步到另一个或多个 MySQL 实例&#xff08;称为从库 Slave&#xff09;的过程。下…

PostgreSQL GIN 索引揭秘

文章目录什么是GIN Index?示例场景GIN Index的原理GIN Index结构MetapageEntriesLeaf PagesEntry page 和 Leaf page 的关系Posting list 和posting tree待处理列表&#xff08;Pending List&#xff09;进阶解读GIN index索引结构总结什么是GIN Index? GIN (Generalized In…

开源多模态OpenFlamingo横空出世,基于Flamingo架构实现图像文本自由对话,重塑人机交互未来

注&#xff1a;此文章内容均节选自充电了么创始人&#xff0c;CEO兼CTO陈敬雷老师的新书《GPT多模态大模型与AI Agent智能体》&#xff08;跟我一起学人工智能&#xff09;【陈敬雷编著】【清华大学出版社】 清华《GPT多模态大模型与AI Agent智能体》书籍配套视频课程【陈敬雷…

电子衍射模拟:基于GPU加速的MATLAB/Julia实现

点击 “AladdinEdu&#xff0c;同学们用得起的【H卡】算力平台”&#xff0c;注册即送-H卡级别算力&#xff0c;80G大显存&#xff0c;按量计费&#xff0c;灵活弹性&#xff0c;顶级配置&#xff0c;学生更享专属优惠。 引言&#xff1a;电子衍射模拟的重要性与计算挑战 电子…

easyExcel动态应用案例

代码链接&#xff1a;https://download.csdn.net/download/ly1h1/919402991.案例说明&#xff1a;1.1.导入功能导入数据实现转换成 List<List<String>> headers和 List<List<String>> datas&#xff0c;后续补充可以与数据模型注解结合&#xff0c;形…

【数据结构入门】排序算法(5):计数排序

目录 1. 比较排序和非比较排序 2. 计数排序的原理 2.1 计数排序的弊端 3.代码复现 3.1 代码分析 3.2 排序核心 3.3 时间、空间复杂度 1. 比较排序和非比较排序 比较排序是根据排序元素的具体数值比较来进行排序&#xff1b;非比较排序则相反&#xff0c;非比较排序例如&…

输入3.8V~32V 输出2A 的DCDC降压芯片SCT9320

同志们&#xff0c;今天来个降压芯片SCT9320。输入3.8V~32V&#xff0c;输出最高可以达到2A。0.8V的参考电压。500k的开关频率。一共八个引脚&#xff0c;两个NC&#xff08;为什么不做成六个引脚呢&#xff1f;&#xff09;。EN引脚悬空或者接到VIN都可以直接启动&#xff0c;…

C++类和对象详解(2);初识类的默认成员函数

1.类的默认成员函数默认成员函数就是用户没有显示实现&#xff0c;编译器会自动生成的成员函数称为默认成员函数。一个类我们不写的情况下编译器会默认生成以下的6个默认成员函数。&#xff08;1&#xff09;构造函数&#xff1a;主要完成初始化的工作&#xff08;2&#xff09…

PLC通信 Tpc客户端Socket

1.PLC通信 namespace _2.PLC通信 {public partial class Form1 : Form{public Form1(){InitializeComponent();}//连接//1.型号: 跟PLC沟通 使用哪个型号的PLC//2.IP 同上//3.机台号:同上//4.插槽号:同上Plc plc new Plc(CpuType.S71200, "192.168.25.80", 0, 1);pr…

Android 开发实战:从零到一集成 espeak-ng 实现中文离线 TTS(无需账号开箱即用)

简介 在移动应用开发中,语音合成(TTS)技术是提升用户体验的重要工具。然而,许多开发者在集成 TTS 时面临依赖网络、需注册账号、功能受限等问题。本文将带你从零开始,通过开源项目 espeak-ng,实现无需账号、开箱即用的中文离线语音播报。 文章将覆盖以下核心内容: esp…

直播APP集成美颜SDK详解:智能美妆功能的开发实战

在这个“颜值即正义”的时代&#xff0c;用户对直播APP的第一印象&#xff0c;往往来自主播的画面质量。高清的视频固然重要&#xff0c;但如果缺少自然美颜和智能美妆功能&#xff0c;观众体验就会大打折扣。于是&#xff0c;美颜SDK成了直播行业的“标配”。今天&#xff0c;…

C++内存管理:new与delete的深层解析

1. 引言在C的世界里&#xff0c;动态内存管理是一个核心话题。对于从C语言过渡到C的开发者来说&#xff0c;一个常见的困惑是&#xff1a;既然C语言的malloc和free依然可以在C中使用&#xff0c;为什么C还要引入new和delete这两个操作符&#xff1f;本文将深入探讨这两对内存管…

【AI开发】【前后端全栈】[特殊字符] AI 时代的快速开发思维

&#x1f680; AI 时代的快速开发思维 —— 以 Django Vue3 为例的前后端分离快捷开发流程 一、AI 时代的开发新思路 在 AI 的加持下&#xff0c;软件开发不再是“纯体力活”&#xff0c;而是 思维工具自动化 的协作。 过去&#xff1a;需求 → 设计 → 开发 → 测试 → 上…

Day24_【深度学习(3)—PyTorch使用—张量的创建和类型转换】

一、创建张量1.张量基本创建方式torch.tensor 根据指定数据创建张量 &#xff08;最重要&#xff09;torch.Tensor 根据形状创建张量, 其也可用来创建指定数据的张量torch.IntTensor、torch.FloatTensor、torch.DoubleTensor 创建指定类型的张量1.1 torch.tensor# 方式一&…

3-12〔OSCP ◈ 研记〕❘ WEB应用攻击▸利用XSS提权

郑重声明&#xff1a; 本文所有安全知识与技术&#xff0c;仅用于探讨、研究及学习&#xff0c;严禁用于违反国家法律法规的非法活动。对于因不当使用相关内容造成的任何损失或法律责任&#xff0c;本人不承担任何责任。 如需转载&#xff0c;请注明出处且不得用于商业盈利。 …

AI 大模型赋能智慧矿山:从政策到落地的全栈解决方案

矿山行业作为能源与工业原料的核心供给端&#xff0c;长期面临 “安全生产压力大、人工效率低、技术落地难” 等痛点。随着 AI 大模型与工业互联网技术的深度融合&#xff0c;智慧矿山已从 “政策引导” 迈入 “规模化落地” 阶段。本文基于 AI 大模型智慧矿山行业解决方案&…

Node.js 项目依赖包管理

h5打开以查看 一、核心理念&#xff1a;从“能用就行”到“精细化管理” 一个规范的依赖管理体系的目标是&#xff1a; 可复现&#xff1a;在任何机器、任何时间都能安装完全一致的依赖&#xff0c;保证构建结果一致。 清晰可控&#xff1a;明确知道每个依赖为何存在&#x…

洛谷P1835素数密度 详解

题目如下&#xff1a;这里面有部分代码比较有意思&#xff1a;1&#xff0c;为何开始先遍历&#xff0c;最终值小于50000&#xff1f;因为题目要求的右边与左边差小于 10^6 &#xff0c;所以最多有10^3个素数&#xff0c;所以保存里面的素数数量大于1000&#xff0c;而50000的化…

突破限制:FileCodeBox远程文件分享新体验

文章目录【视频教程】1.Docker部署2.简单使用演示3. 安装cpolar内网穿透4. 配置公网地址5. 配置固定公网地址在隐私日益重要的今天&#xff0c;FileCodeBox与cpolar的协同为文件传输提供了安全高效的解决方案。通过消除公网IP限制和隐私顾虑&#xff0c;让每个人都能掌控自己的…