You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何用C++编写支持延迟回调注册与到期执行的小型库

实现思路与代码参考

疑问解答

  • 注册功能逻辑:注册时不会阻塞等待,仅会把回调、绑定的参数、计算好的绝对触发时间存到内部存储中,等待后续execute调用时统一判断执行
  • 回调参数支持:可以通过lambda捕获或std::bind实现任意数量、类型的参数绑定,不需要额外编写多套重载适配不同参数的回调

核心结构设计

  • 回调存储结构:每个待执行回调需要存储触发绝对时间、绑定完参数的可执行对象两个核心字段,选择按触发时间升序排序的容器(如std::multimap)存储可提升执行效率,不用每次遍历全量回调
  • 调度器类核心接口:
    • register_callback:接收延迟秒数、回调函数、可变参数,计算绝对触发时间,把参数绑定到回调后存入容器
    • execute:获取当前时间,取出所有触发时间小于等于当前时间的回调执行,执行后从容器删除(满足一次性执行要求)

伪代码参考

// 回调项定义
struct CallbackItem {
    TimePoint trigger_time; // 绝对触发时间
    function<void()> bound_callback; // 已绑定参数的可执行对象
    // 按触发时间升序排序重载
    bool operator<(const CallbackItem& other) const {
        return trigger_time < other.trigger_time;
    }
}

class CallbackScheduler {
private:
    sorted_container<CallbackItem> pending_callbacks; // 按触发时间排序的待执行回调容器
public:
    void register_callback(double delay_seconds, 回调函数, 可选参数列表) {
        // 计算触发的绝对时间 = 当前时间 + 延迟秒数
        trigger_time = current_steady_time() + seconds(delay_seconds);
        // 把可选参数绑定到回调函数上,生成无参可执行对象
        bound_callback = 绑定参数(回调函数, 可选参数列表);
        // 存入待执行容器
        pending_callbacks.insert(CallbackItem{trigger_time, bound_callback});
    }

    void execute() {
        now = current_steady_time();
        // 找到第一个触发时间晚于当前时间的回调,前面的所有回调均已到期
        end_iter = 第一个未到期回调的位置;
        // 遍历执行所有到期回调
        for (iter = 容器头; iter != end_iter; iter++) {
            iter->bound_callback();
        }
        // 批量删除所有已执行的回调
        pending_callbacks.erase(容器头, end_iter);
    }
}

完整可运行实现

#include <iostream>
#include <chrono>
#include <functional>
#include <map>
#include <thread>

using TimePoint = std::chrono::steady_clock::time_point;
using Seconds = std::chrono::duration<double>;

class CallbackScheduler {
private:
    // 按触发时间升序存储回调,key为触发时间,value为绑定好参数的回调
    std::multimap<TimePoint, std::function<void()>> pending_callbacks;
public:
    // 注册回调接口:延迟秒数,回调函数,任意数量可选参数
    template<typename Func, typename... Args>
    void register_callback(double delay_seconds, Func&& func, Args&&... args) {
        TimePoint trigger_time = std::chrono::steady_clock::now() + Seconds(delay_seconds);
        // 绑定参数生成无参可执行对象
        std::function<void()> bound_callback = [func = std::forward<Func>(func), ...args = std::forward<Args>(args)]() mutable {
            func(args...);
        };
        pending_callbacks.insert({trigger_time, std::move(bound_callback)});
    }

    // 执行所有到期回调
    void execute() {
        TimePoint now = std::chrono::steady_clock::now();
        // 找到第一个未到期的回调位置,之前的全部到期
        auto end_iter = pending_callbacks.upper_bound(now);
        // 遍历执行所有到期回调
        for (auto iter = pending_callbacks.begin(); iter != end_iter; ++iter) {
            iter->second();
        }
        // 批量删除已执行的回调
        pending_callbacks.erase(pending_callbacks.begin(), end_iter);
    }
};

// 测试用回调函数1:带int参数
void print_num(int num) {
    std::cout << "回调触发:打印数字 " << num << std::endl;
}

// 测试用回调函数2:带字符串参数
void print_msg(const std::string& msg) {
    std::cout << "回调触发:打印消息 " << msg << std::endl;
}

int main() {
    CallbackScheduler scheduler;

    // 注册3个测试回调
    scheduler.register_callback(1.0, print_num, 100); // 1秒后触发
    scheduler.register_callback(2.0, print_msg, "Hello World"); // 2秒后触发
    scheduler.register_callback(1.5, [](){ std::cout << "回调触发:lambda无参回调" << std::endl; }); // 1.5秒后触发

    // 模拟业务循环,每500ms调用一次execute
    for (int i = 0; i < 5; ++i) {
        std::cout << "第" << i+1 << "次调用execute" << std::endl;
        scheduler.execute();
        std::this_thread::sleep_for(std::chrono::milliseconds(500));
    }

    return 0;
}

内容的提问来源于stack exchange,提问作者Ashish

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.24 22:15:04