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(¤t, 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(¤t, 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; }
使用说明
- 编译:
gcc -o time time.c - 执行示例:
- 简单命令:
./time ls - 带参数的命令:
./time sleep 2
- 简单命令:
内容的提问来源于stack exchange,提问作者Hiếu Võ Trần Minh
相关产品推荐
相关产品推荐

