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

C程序测量命令执行耗时问题:共享内存异常与命令传参疑问

命令行命令耗时测量程序问题排查与解决

问题描述

我正在编写一款用于测量命令行命令执行耗时的C程序,设计思路是:通过fork创建子进程执行目标命令并记录启动时间戳,父进程等待子进程终止后记录结束时间,耗时为两者时间差,计划用共享内存实现父子进程通信。但目前父进程无法获取子进程的启动时间,怀疑共享内存实现有问题,代码如下:

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

#define BUFFER_SIZE 10

typedef struct {
    time_t sec;
    suseconds_t msec;
} item;

item buffer[BUFFER_SIZE];
int in = 0;
int out = 0;

int main()
{
pid_t pid;
    char *ls;
    scanf("%s", ls);

    /* fork a child process */
    pid = fork();

    if (pid == 0) { /* child process */
        struct timeval current;
        gettimeofday(&current, NULL);
        
        item starting_time;
        starting_time.sec = current.tv_sec;
        starting_time.msec = current.tv_usec;
        
        buffer[in] = starting_time;
        execlp(ls, "ls", NULL);
    }
    else { /* parent process */
        wait(NULL);
        
        item starting_time;
        starting_time = buffer[out];
        
        struct timeval current;
        gettimeofday(&current, NULL);
        
        long seconds = current.tv_sec - starting_time.sec;
        printf("The elapsed time is: %ld", seconds);
        
    }
}

另外,不清楚如何像示例那样在终端执行编译后的程序时附带命令参数,示例如下:

./time ls
time.c
time

Elapsed time: 0.25422

问题分析与修复

1. 核心问题:进程内存隔离导致数据无法共享

你代码里的buffer是全局变量,但fork后父子进程拥有完全独立的地址空间,子进程修改的buffer是自己内存空间的副本,父进程根本看不到。没必要用复杂的共享内存,有更简洁高效的方案:父进程在fork之前记录时间——因为fork完成后子进程会立即启动,这个时间和子进程实际启动时间的误差可以忽略不计,完全满足耗时测量的精度需求。

2. 代码中的其他致命错误

  • char *ls; scanf("%s", ls);:ls是未初始化的野指针,直接scanf会触发内存崩溃,必须用数组或提前分配内存。
  • execlp(ls, "ls", NULL);:第二个参数是命令的argv[0],硬写为"ls"会导致输入其他命令时执行异常,应该和目标命令保持一致。
  • 只计算秒数差,丢弃了微秒数据,导致精度严重丢失。

3. 命令行参数传递实现

不需要用scanf读取命令,直接利用main函数的argc和argv参数即可实现./time ls这种调用方式。

修复后的完整代码

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

int main(int argc, char *argv[]) {
    // 检查命令行参数合法性
    if (argc < 2) {
        fprintf(stderr, "用法: %s <命令> [命令参数]\n", argv[0]);
        return 1;
    }

    pid_t pid;
    struct timeval start_time, end_time;

    // 父进程在fork前记录时间,近似子进程启动时间
    gettimeofday(&start_time, NULL);

    pid = fork();
    if (pid == 0) {
        // 子进程执行目标命令,execvp支持带参数的命令(如ls -l)
        execvp(argv[1], &argv[1]);
        // 如果execvp返回,说明命令执行失败
        perror("命令执行失败");
        return 1;
    } else if (pid > 0) {
        // 父进程等待子进程结束
        wait(NULL);
        gettimeofday(&end_time, NULL);

        // 计算总耗时(保留微秒精度)
        long seconds = end_time.tv_sec - start_time.tv_sec;
        long microseconds = end_time.tv_usec - start_time.tv_usec;
        double elapsed = seconds + microseconds / 1e6;

        printf("\nElapsed time: %.5f\n", elapsed);
    } else {
        perror("创建子进程失败");
        return 1;
    }

    return 0;
}

使用说明

  1. 编译:gcc -o time time.c
  2. 执行示例:
    • 简单命令:./time ls
    • 带参数的命令:./time sleep 2

内容的提问来源于stack exchange,提问作者Hiếu Võ Trần Minh

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.28 05:13:17