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

C语言中测量子进程退出时长异常问题排查

问题根源分析

1. clock()函数的误用

你用clock()计时是核心错误:这个函数统计的是当前进程消耗的CPU时间,不是实际流逝的"墙上时间"。

  • 父进程调用fork()后,子进程独立运行,它的CPU时间不会被父进程的clock()统计。
  • 父进程在waitpid()时处于阻塞状态,几乎不消耗CPU,所以end - begin的结果只是父进程在fork、waitpid这些操作上的CPU开销,和子进程实际运行的2秒完全无关,数值自然不稳定且远小于预期。

2. 时间单位处理错误

就算clock()用对了,你当前的代码也没做单位转换:clock()的返回值单位是CLOCKS_PER_SEC(通常是1000000)分之一秒,直接输出并标注ms是错误的,正确转换应该是(end - begin) * 1000.0 / CLOCKS_PER_SEC才能得到毫秒数。

修正方案

改用墙上时间计时,推荐用clock_gettime()(POSIX标准,精度更高),它的CLOCK_MONOTONIC时钟是单调递增的,不会因为系统时间调整产生误差,适合计时需求:

修改头文件中的计时逻辑:

#include <stdio.h>
#include <unistd.h>
#include <wait.h>
#include <sys/types.h>
#include <time.h>

#define __MINTEST_SAFE_BLOCK(block) \
    do                              \
    {                               \
        block                       \
    } while (0)

#define TEST_CASE(test) static void test(void)

#define TEST_SUITE(suite) static void suite(void)

#define __RUN_TEST_CASE(test, caller) __MINTEST_SAFE_BLOCK(                                               \
    pid_t pid;                                                                                            \
    int status;                                                                                           \
    struct timespec begin, end;                                                                           \
    double time_spent;                                                                                    \
                                                                                                          \
    clock_gettime(CLOCK_MONOTONIC, &begin);                                                               \
    pid = fork();                                                                                         \
    switch (pid) {                                                                                        \
        case -1:                                                                                          \
            perror("fork");                                                                               \
            break;                                                                                        \
        case 0:                                                                                           \
            test();                                                                                       \
            _exit(0); /* 确保子进程直接退出,避免执行父进程后续代码 */                                    \
            break;                                                                                        \
        default:                                                                                          \
            waitpid(pid, &status, 0);                                                                     \
            clock_gettime(CLOCK_MONOTONIC, &end);                                                         \
            /* 计算毫秒数:秒转毫秒 + 纳秒转毫秒 */                                                        \
            time_spent = (end.tv_sec - begin.tv_sec) * 1000.0 + (end.tv_nsec - begin.tv_nsec) / 1000000.0;\
            if (WIFEXITED(status))                                                                        \
            {                                                                                             \
                printf("%s:%s passed after %.3fms [%d]\n", caller, #test, time_spent, WEXITSTATUS(status));\
            }                                                                                             \
            else if (WIFSIGNALED(status))                                                                 \
            {                                                                                             \
                printf("%s:%s failed after %.3fms [%d]\n", caller, #test, time_spent, WTERMSIG(status));   \
            }                                                                                             \
            break;                                                                                        \
    })

#define RUN_TEST_CASE(test) __RUN_TEST_CASE(test, __func__)

#define RUN_TEST_SUITE(suite) suite()

额外优化点:

  • 子进程执行完test()后调用_exit(0),避免子进程意外执行父进程的后续代码,逻辑更严谨。
  • 时间计算保留三位小数,输出结果更清晰。
测试验证

修改后运行你的测试代码,会输出类似:

In test
test_suite:test_something failed after 2000.123ms [11]

结果符合预期的2秒左右时长,且数值稳定。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.06 07:44:54