0

0

C++怎么实现定时器_C++时间控制教程【触发】

穿越時空

穿越時空

发布时间:2026-02-24 12:11:52

|

401人浏览过

|

来源于php中文网

原创

std::this_thread::sleep_for 不能当定时器用,因其仅阻塞当前线程、无回调、不可取消、不自动重复,仅适用于单次延时;伪定时循环会导致卡死、响应失效和精度偏差。

c++怎么实现定时器_c++时间控制教程【触发】

std::this_thread::sleep_for 为什么不能当定时器用

它只是让当前线程暂停,不触发回调、不自动重复、无法取消,本质是“延时”,不是“定时器”。真要轮询或等待某个时间点,它能凑合;但想在后台隔几秒执行一次 log_status() 或超时后发个通知,它直接失效。

常见错误现象:std::this_thread::sleep_for 套在 while 循环里做“伪定时”,结果主线程卡死、无法响应退出信号、精度漂移严重(尤其在 Windows 上实际休眠比指定时间长)。

  • 只适合单次阻塞等待,比如初始化后等 100ms 再继续
  • 不要用它模拟周期任务——CPU 空转 + sleep 组合既耗电又不准
  • 如果必须用,优先搭配 std::chrono::steady_clock,别用 system_clock(可能被系统时间调整拖垮)

std::thread + std::condition_variable 实现可取消的单次定时器

这是 C++11 起最轻量、无外部依赖的靠谱方案,核心是让一个独立线程等待条件变量超时,到点后通知主逻辑,同时支持中途调用 cancel() 提前唤醒。

使用场景:HTTP 请求超时控制、资源锁自动释放、GUI 操作倒计时反馈。

立即学习C++免费学习笔记(深入)”;

关键参数差异:std::condition_variable::wait_until 接收的是绝对时间点(std::chrono::time_point),不是间隔;而 wait_for 是相对时长,容易因系统调度偏差累积误差。

Hotpot.ai
Hotpot.ai

AI工具箱(图像、游戏和写作系列工具)

下载

示例片段:

class SimpleTimer {
    std::thread t_;
    std::mutex mtx_;
    std::condition_variable cv_;
    bool cancelled_ = false;

public:
    template<typename Rep, typename Period, typename F, typename... Args>
    SimpleTimer(std::chrono::duration<Rep, Period> delay, F&& f, Args&&... args) {
        t_ = std::thread([this, delay, f = std::forward<F>(f), 
                          args = std::make_tuple(std::forward<Args>(args)...)]() mutable {
            auto tp = std::chrono::steady_clock::now() + delay;
            std::unique_lock<std::mutex> lk(mtx_);
            if (cv_.wait_until(lk, tp, [this]{ return cancelled_; })) {
                return; // 被 cancel
            }
            std::apply(f, args);
        });
    }

    void cancel() {
        {
            std::lock_guard<std::mutex> lk(mtx_);
            cancelled_ = true;
        }
        cv_.notify_all();
    }

    ~SimpleTimer() {
        if (t_.joinable()) t_.join();
    }
};

Windows 上用 SetTimer / CreateWaitableTimer 容易踩的坑

这两个 API 表面简单,但和 C++ 对象生命周期一结合就出事。典型问题是:定时器回调函数里访问已析构的对象成员,或者 SetTimer 返回的 UINT_PTR 被当成裸指针传进回调,结果对象早没了。

性能影响:Windows GUI 线程的 SetTimer 会向消息队列投递 WM_TIMER,若主线程忙于计算,消息积压,定时器就“跳帧”;而 CreateWaitableTimer 配合 WaitForSingleObjectEx 更准,但必须手动管理等待线程。

  • 绝不要在回调里直接调用 this->do_something() —— 改用静态函数 + SetWindowLongPtr 存句柄,或用 std::shared_ptr 持有对象并传入 lambda 捕获
  • CreateWaitableTimerbManualReset 设为 false 才能自动重置,否则第二次 WaitForSingleObject 会立刻返回
  • 跨 DLL 边界时,确保回调函数是 __stdcall,否则栈被破坏

Linux 下 timerfd_create 怎么和 epoll 配合

这是 Linux 原生、高效、可嵌入事件循环的方案,timerfd_create 返回一个文件描述符,到期时 epoll_wait 就能感知到可读事件,不用额外线程。

兼容性注意:glibc 2.8+、内核 2.6.25+ 才支持;macOS 和 Windows 完全不支持,别写死了。

容易漏的点:timerfd_settimeit_value 设为 0 表示“只设置间隔,不立即触发”,但很多人误设成非零导致第一次触发提前;另外,每次 read timerfd 必须读 8 字节(uint64_t),否则下次 epoll_wait 不再通知。

  • CLOCK_MONOTONIC,别用 CLOCK_REALTIME(NTP 调整会让定时器乱跳)
  • struct itimerspec 的 it_interval 设为 0 表示只触发一次
  • 务必检查 read() 返回值,少于 8 字节说明出错或被中断
C++ 里没有“开箱即用”的跨平台定时器抽象,每个方案都得自己兜底处理取消、销毁、线程安全。最麻烦的不是写代码,而是厘清“谁负责 stop、谁负责 join、谁负责清理资源”——这些边界一旦模糊,use-after-freethread leak 就跟着来了。

热门AI工具

更多
DeepSeek
DeepSeek

幻方量化公司旗下的开源大模型平台

豆包大模型
豆包大模型

字节跳动自主研发的一系列大型语言模型

通义千问
通义千问

阿里巴巴推出的全能AI助手

腾讯元宝
腾讯元宝

腾讯混元平台推出的AI助手

文心一言
文心一言

文心一言是百度开发的AI聊天机器人,通过对话可以生成各种形式的内容。

讯飞写作
讯飞写作

基于讯飞星火大模型的AI写作工具,可以快速生成新闻稿件、品宣文案、工作总结、心得体会等各种文文稿

即梦AI
即梦AI

一站式AI创作平台,免费AI图片和视频生成。

ChatGPT
ChatGPT

最最强大的AI聊天机器人程序,ChatGPT不单是聊天机器人,还能进行撰写邮件、视频脚本、文案、翻译、代码等任务。

相关专题

更多
while的用法
while的用法

while的用法是“while 条件: 代码块”,条件是一个表达式,当条件为真时,执行代码块,然后再次判断条件是否为真,如果为真则继续执行代码块,直到条件为假为止。本专题为大家提供while相关的文章、下载、课程内容,供大家免费下载体验。

103

2023.09.25

lambda表达式
lambda表达式

Lambda表达式是一种匿名函数的简洁表示方式,它可以在需要函数作为参数的地方使用,并提供了一种更简洁、更灵活的编码方式,其语法为“lambda 参数列表: 表达式”,参数列表是函数的参数,可以包含一个或多个参数,用逗号分隔,表达式是函数的执行体,用于定义函数的具体操作。本专题为大家提供lambda表达式相关的文章、下载、课程内容,供大家免费下载体验。

212

2023.09.15

python lambda函数
python lambda函数

本专题整合了python lambda函数用法详解,阅读专题下面的文章了解更多详细内容。

192

2025.11.08

Python lambda详解
Python lambda详解

本专题整合了Python lambda函数相关教程,阅读下面的文章了解更多详细内容。

60

2026.01.05

堆和栈的区别
堆和栈的区别

堆和栈的区别:1、内存分配方式不同;2、大小不同;3、数据访问方式不同;4、数据的生命周期。本专题为大家提供堆和栈的区别的相关的文章、下载、课程内容,供大家免费下载体验。

422

2023.07.18

堆和栈区别
堆和栈区别

堆(Heap)和栈(Stack)是计算机中两种常见的内存分配机制。它们在内存管理的方式、分配方式以及使用场景上有很大的区别。本文将详细介绍堆和栈的特点、区别以及各自的使用场景。php中文网给大家带来了相关的教程以及文章欢迎大家前来学习阅读。

595

2023.08.10

线程和进程的区别
线程和进程的区别

线程和进程的区别:线程是进程的一部分,用于实现并发和并行操作,而线程共享进程的资源,通信更方便快捷,切换开销较小。本专题为大家提供线程和进程区别相关的各种文章、以及下载和课程。

719

2023.08.10

线程和进程的区别
线程和进程的区别

线程和进程的区别:线程是进程的一部分,用于实现并发和并行操作,而线程共享进程的资源,通信更方便快捷,切换开销较小。本专题为大家提供线程和进程区别相关的各种文章、以及下载和课程。

719

2023.08.10

苹果官网入口与在线访问指南_中国站点快速直达与iPhone查看方法
苹果官网入口与在线访问指南_中国站点快速直达与iPhone查看方法

本专题汇总苹果官网最新可用入口及中国站点访问方式,涵盖官网直达链接、iPhone官方页面查看方法与常见访问说明,帮助用户快速进入苹果官方网站,便捷了解产品信息与官方服务。

2

2026.02.24

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
C# 教程
C# 教程

共94课时 | 10万人学习

C 教程
C 教程

共75课时 | 4.9万人学习

C++教程
C++教程

共115课时 | 19.1万人学习

关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号 技术交流群
PHP中文网订阅号
每天精选资源文章推送

Copyright 2014-2026 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号