如何让C语言while(1)循环以固定10000Hz频率运行并满足双退出条件?
实现固定10000Hz频率的C语言循环(多进程时间跟踪版)
要解决循环频率不准、退出条件不精准的问题,我们可以用多进程分离计时与计算任务的方案:主进程负责维持固定频率的循环执行计算,子进程专门跟踪运行时长,到点触发退出;同时主进程自身监控迭代次数,满足任一退出条件即终止循环。
核心思路
- 主进程:执行循环内的计算逻辑,通过高精度定时器控制每次循环的总周期(100us,对应10000Hz),同时统计迭代次数,达到指定次数时主动退出。
- 子进程:独立跟踪运行时长,当达到设定的最大运行时间时,向主进程发送终止信号,触发主进程退出循环。
完整代码实现
#include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <signal.h> #include <time.h> #include <sys/types.h> #include <sys/wait.h> #define TARGET_FREQ 10000 // 目标频率:10000Hz #define PERIOD_NS (1000000000 / TARGET_FREQ) // 单次循环周期:100微秒(100000纳秒) volatile sig_atomic_t exit_flag = 0; // 信号处理函数:收到子进程的终止信号时设置退出标志 void sig_handler(int signum) { exit_flag = 1; } int main(int argc, char *argv[]) { if (argc != 3) { fprintf(stderr, "用法: %s <最大运行时长(秒)> <最大迭代次数>\n", argv[0]); exit(EXIT_FAILURE); } const int max_seconds = atoi(argv[1]); const int max_iterations = atoi(argv[2]); int loop_count = 0; // 注册SIGINT信号处理,响应子进程的终止通知 if (signal(SIGINT, sig_handler) == SIG_ERR) { perror("注册信号处理失败"); exit(EXIT_FAILURE); } // 创建子进程负责计时 pid_t pid = fork(); if (pid < 0) { perror("创建子进程失败"); exit(EXIT_FAILURE); } else if (pid == 0) { // 子进程逻辑:等待指定时长后向主进程发送终止信号 sleep(max_seconds); kill(getppid(), SIGINT); exit(EXIT_SUCCESS); } else { // 主进程逻辑:维持固定频率循环 struct timespec start, end, sleep_time; long long elapsed_ns; while (!exit_flag && loop_count < max_iterations) { // 记录循环开始时间(使用单调时钟,不受系统时间调整影响) clock_gettime(CLOCK_MONOTONIC, &start); // -------------------------- // 此处替换为你的计算逻辑 // Some calculations // -------------------------- // 更新迭代次数 loop_count++; // 计算当前循环已耗时 clock_gettime(CLOCK_MONOTONIC, &end); elapsed_ns = (end.tv_sec - start.tv_sec) * 100000000LL + (end.tv_nsec - start.tv_nsec); // 补全剩余时间,保证单次循环总时长为PERIOD_NS if (elapsed_ns < PERIOD_NS) { sleep_time.tv_sec = 0; sleep_time.tv_nsec = PERIOD_NS - elapsed_ns; // 处理nanosleep被信号打断的情况,确保休眠足够时长 while (nanosleep(&sleep_time, &sleep_time) != 0); } // 若计算耗时超过周期,直接进入下一次循环(无法保证频率,只能尽量追赶) } // 清理子进程资源 kill(pid, SIGKILL); waitpid(pid, NULL, 0); printf("循环终止:实际迭代次数=%d,设定运行时长=%d秒\n", loop_count, max_seconds); } return EXIT_SUCCESS; }
关键细节说明
高精度计时:
使用CLOCK_MONOTONIC时钟,它是单调递增的,不会受系统时间修改(如NTP同步、手动调时间)影响,保证计时的准确性。信号安全的退出控制:
用volatile sig_atomic_t类型的exit_flag,确保信号处理函数修改的变量能被主进程及时感知,同时避免竞态条件。周期补时逻辑:
每次循环计算已消耗的时间,若小于目标周期(100us),则用nanosleep()休眠剩余时间;若计算耗时超过周期,直接进入下一次循环(这种情况无法保证频率,需优化计算逻辑)。高精度子进程计时(可选):
若需要秒级以下的精确时长控制(如1.5秒),可将子进程的sleep()替换为基于clock_gettime的循环计时:struct timespec start, current; clock_gettime(CLOCK_MONOTONIC, &start); while (1) { clock_gettime(CLOCK_MONOTONIC, ¤t); long long elapsed = (current.tv_sec - start.tv_sec) * 100000000LL + (current.tv_nsec - start.tv_nsec); if (elapsed >= (long long)max_seconds * 1000000000LL) { kill(getppid(), SIGINT); break; } // 短休眠避免空循环占用CPU nanosleep(&(struct timespec){0, 1000000}, NULL); }
编译与运行
- 编译命令(部分系统需链接实时库):
gcc -o fixed_freq_loop fixed_freq_loop.c -lrt - 运行示例(运行1秒或10000次迭代,满足任一条件即退出):
./fixed_freq_loop 1 10000
内容的提问来源于stack exchange,提问作者Raghuvir
相关产品推荐
相关产品推荐

