无法在C(popen)中执行命令执行时间?

问题描述:

我一直在试图调用popen来完成需要多长时间。 popen初始化一个进程,然后创建一个管道,分叉并调用shell。在我的具体情况下,我正在使用该呼叫读取另一个节目stdout输出。无法在C(popen)中执行命令执行时间?

问题:我期待着我所做的调用返回程序执行所花费的正确时间长度(测试程序大约需要15秒)。我得到的是该程序完全没有花时间完成(0.000223s)。尽管我尝试了各种各样的功能,但我似乎无法正确计时。

这是我的问题的一个可重现的例子。它是由定时程序和定时程序运行的子计划(子大约需要15秒到我的系统上运行):

#include <stdio.h> 
#include <stdlib.h> 
#include <time.h> 
#include <sys/time.h> 
#ifdef __MACH__ 
#include <mach/clock.h> 
#include <mach/mach.h> 
#endif 

#define MAXBUF 10 

static void gettime (struct timespec *t) { 
#ifdef __MACH__ 
    clock_serv_t cclock; 
    mach_timespec_t mts; 
    host_get_clock_service(mach_host_self(), REALTIME_CLOCK, &cclock); 
    clock_get_time(cclock, &mts); 
    mach_port_deallocate(mach_task_self(), cclock); 
    t->tv_sec = mts.tv_sec; 
    t->tv_nsec = mts.tv_nsec; 
#else 
    clock_gettime(CLOCK_REALTIME, t); 
#endif 
} 

int main (void) { 
    FILE *fp; 
    struct timespec tic, toc; 
    char *executableName = "./a.out"; 
    char answer[MAXBUF]; 

    gettime(&tic); 
    if ((fp = popen(executableName, "r")) == NULL) { 
     fprintf(stderr, "The file couldn't be opened.\n"); 
     return 1; 
    } 
    gettime(&toc); 

    fgets(answer, MAXBUF, fp); 
    double elapsed = (double)(toc.tv_nsec - tic.tv_nsec)/1E9; 
    fprintf(stdout, "The program says %s, and took %fs to run!\n", answer, elapsed); 

    pclose(fp); 
    return 0; 
} 

这里是孩子的程序:

#include <stdio.h> 
#include <stdlib.h> 

int timeWastingFunction (long long n) { 
    if ((n % 2) == 0) { 
     return 1; 
    } 
    for (int i = 1; i < (n/2); i += 2) { 
     if ((n % i) == 0) { 
      return 1; 
     } 
    } 
    return 0; 
} 

int main (void) { 
    int start = 687217000; 

    while (start--) { 
     timeWastingFunction(start); 
    } 
    fprintf(stdout, "Hello!"); 
    return 0; 
} 

这可能看起来有点过头,但我以前曾尝试使用clock_t(基于CPU的时序工具)来完成时序,并从中获得相同的答案。因此,我尝试了this解决方案,您可以在上面看到。我选择了:CLOCK_REALTIME,因为它似乎适合这份工作。不幸的是我没有选择指定这个时钟是在每个进程还是每个线程上(尽管我希望它是独立于进程的)。

注:我还没有使用gettimeofday还没有试过,但我不想因为它显然不适合定时这种方式,依赖于系统的日期用它来,并赞成被淘汰clock_gettime

编辑:只是要清楚,当我运行这是程序调用popen实际上拖延了15秒其它程序需要运行,打印“错误”的时间之前发生了什么。它不会立即打印表明它没有等待电话完成的时间。

+4

您使用clock_gettime'的'是正确的[和比'gettimeofday'更受欢迎]。你的问题是'popen'立即返回[几乎]。它不会等待目标进程完成。尝试:gettime(&tic); popen(); ...; pclose(); gettime(&toc);' –

+0

@CraigEstey谢谢!如果我想使用我打开的文件,但是这需要我重新打开(在这种情况下运行) )或者有没有办法在没有重新开放的开销的情况下使用它,而不会中毒计时? – Micrified

+1

请注意,macOS Sierra(10.12.x)现在确实支持'clock_gettime()',但是如果您在Sierra上编译代码以在较旧的系统上运行,您仍然无法使用它(如果您在较旧版本的Mac OS X上编译,则无法使用它,因此无法(很容易)使用它) –

popen()只有叉和打开管道。您的测试仅显示用popen()创建孩子和管道的时间。

一种简单的方法来解决你的问题是你pclose()后得到的时间,注意将不完美的,因为当你读你的孩子中的数据回报,它可以呼叫之前,完成对pclose()

加您的解决方案,以获得结果坏了,你只能让纳秒之间的区别,我发现git的一个解决方案:

void timespec_diff(struct timespec *start, struct timespec *stop, 
        struct timespec *result) 
{ 
    if ((stop->tv_nsec - start->tv_nsec) < 0) { 
     result->tv_sec = stop->tv_sec - start->tv_sec - 1; 
     result->tv_nsec = stop->tv_nsec - start->tv_nsec + 1000000000; 
    } else { 
     result->tv_sec = stop->tv_sec - start->tv_sec; 
     result->tv_nsec = stop->tv_nsec - start->tv_nsec; 
    } 

    return; 
} 

的最后一件事是,CLOCK_REALTIME应,如果你想的日期使用。在这里你只需要一段时间。因此,如果您的系统可用,则应使用CLOCK_MONOTONIC,因为CLOCK_REALTIME可以回滚。 (REALTIME_CLOCKhost_get_clock_service()接缝也是单调的)。

CLOCK_MONOTONIC:无法设置的时钟,表示从某个非指定起点开始的单调时间。

REALTIME_CLOCK:一种中等分辨率的时钟服务,通常跟踪自系统上次引导以来的时间。

所以工作代码可能看起来像:

int main (void) { 
    FILE *fp; 
    struct timespec tic, toc; 
    char *executableName = "./a.out"; 
    char answer[MAXBUF]; 

    gettime(&tic); 
    if ((fp = popen(executableName, "r")) == NULL) { 
     fprintf(stderr, "The file couldn't be opened.\n"); 
     return 1; 
    } 

    fgets(answer, MAXBUF, fp); 

    pclose(fp); 
    gettime(&toc); 
    struct timespec result; 
    timespec_diff(&tic, &toc, &result); 
    fprintf(stdout, "The program says %s, and took %lld.%.9lds\n", answer, (long long)result.tv_sec, result.tv_nsec); 

    return 0; 
} 

信用: