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

嵌入式C/C++按特定速率调用函数:最佳实践、示例及跨平台实现问询

嵌入式C/C++按特定速率调用函数的最佳实践与示例

核心原则

  • 拒绝忙等循环:纯delay会浪费CPU资源,尤其在Jetson和笔记本这类带OS的平台上完全没必要
  • 依赖系统时钟/定时器:优先用平台提供的成熟定时器API,避免自己造轮子
  • 控制任务执行时长:任务执行时间必须远小于调度周期(比如100ms周期的任务,执行时间要压在几ms内),否则会拖垮整个调度节奏
  • 跨平台一致性:用统一的单调时间基准,屏蔽底层平台差异

分平台实现方案

1. Jetson-Nano(Linux平台)

Linux下有两种主流方案,按需选择:

  • 线程+clock_nanosleep:新手友好,逻辑简单,用线程循环等待到指定时间再执行任务
  • POSIX定时器:精度更高,支持信号触发或线程回调,适合对精度要求苛刻的场景
  • 可选优化:将调度线程设为实时优先级,减少Linux调度器的延迟

2. 笔记本(跨Windows/Linux)

直接用C++11及以上标准库的<chrono>和<thread>组件,实现跨平台通用的调度逻辑,保证Jetson和笔记本上的执行速率完全一致。

最优推荐方案(新手友好+跨平台)

优先选择C++标准库实现的线程+绝对时间等待,既跨平台,又能避免累计误差,代码易读易维护。如果Jetson需要更高精度,再切换到POSIX定时器。

跨平台通用示例代码

#include <iostream>
#include <thread>
#include <chrono>
#include <atomic>
#include <mutex>

// 原子变量控制调度启停
std::atomic<bool> g_running(true);
// 互斥锁保护控制台输出(避免多线程打印混乱)
std::mutex g_print_mutex;

// 50ms周期任务
void task_50ms() {
    static int count = 0;
    std::lock_guard<std::mutex> lock(g_print_mutex);
    std::cout << "50ms任务执行,次数:" << ++count << std::endl;
}

// 100ms周期任务
void task_100ms() {
    static int count = 0;
    std::lock_guard<std::mutex> lock(g_print_mutex);
    std::cout << "100ms任务执行,次数:" << ++count << std::endl;
}

// 通用调度模板函数
template<typename Func>
void schedule_task(Func task, std::chrono::milliseconds period) {
    using namespace std::chrono;
    auto next_run_time = steady_clock::now() + period;

    while (g_running) {
        // 等待到下一次执行的绝对时间(避免累计误差)
        std::this_thread::sleep_until(next_run_time);

        // 执行任务
        task();

        // 更新下一次执行时间
        next_run_time += period;
    }
}

int main() {
    // 启动两个调度线程
    std::thread t1(schedule_task<decltype(task_50ms)>, task_50ms, 50ms);
    std::thread t2(schedule_task<decltype(task_100ms)>, task_100ms, 100ms);

    // 运行10秒后停止
    std::this_thread::sleep_for(10s);
    g_running = false;

    // 等待线程结束
    t1.join();
    t2.join();

    return 0;
}

Jetson-Nano高精度优化示例(POSIX定时器)

如果需要微秒级精度,可使用Linux专属的POSIX定时器:

#include <iostream>
#include <signal.h>
#include <time.h>
#include <atomic>
#include <mutex>

std::atomic<bool> g_running(true);
std::mutex g_print_mutex;

void task_100ms(union sigval arg) {
    static int count = 0;
    std::lock_guard<std::mutex> lock(g_print_mutex);
    std::cout << "100ms任务执行(POSIX定时器),次数:" << ++count << std::endl;
}

int main() {
    timer_t timer_id;
    struct sigevent sev;
    struct itimerspec its;

    // 设置线程回调模式
    sev.sigev_notify = SIGEV_THREAD;
    sev.sigev_notify_function = task_100ms;
    sev.sigev_notify_attributes = nullptr;

    // 创建基于单调时钟的定时器
    if (timer_create(CLOCK_MONOTONIC, &sev, &timer_id) == -1) {
        perror("timer_create失败");
        return 1;
    }

    // 设置定时器参数:首次100ms后执行,之后每100ms执行一次
    its.it_value.tv_sec = 0;
    its.it_value.tv_nsec = 100 * 1000 * 1000; // 100ms
    its.it_interval = its.it_value;

    // 启动定时器
    if (timer_settime(timer_id, 0, &its, nullptr) == -1) {
        perror("timer_settime失败");
        return 1;
    }

    // 运行10秒后停止
    sleep(10);
    g_running = false;
    timer_delete(timer_id);

    return 0;
}

关键注意事项

  • 用steady_clock(单调时钟)而非system_clock:避免系统时间调整导致的调度异常
  • 线程安全:多线程调度时,共享资源必须用互斥锁保护
  • 任务超时处理:如果任务执行时间超过周期,要优化任务逻辑或拆分任务,避免调度延迟累积

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.16 09:05:22