运行代码x时间

时间:2016-08-10 21:48:32

标签: c unix

前言,我在使用gcc的Unix(linux)系统上。

我所坚持的是如何准确地实现在一段时间内运行代码段的方法。

以下是我一直在使用的一个例子:

struct timeb start, check;
int64_t duration = 10000;
int64_t elapsed = 0;

ftime(&start);

while ( elapsed < duration ) {
    // do a set of tasks
    ftime(&check);
    elapsed += ((check.time - start.time) * 1000)  + (check.millitm - start.millitm);
}

我原本以为这会持续10000毫秒或10秒,但它几乎不会立即发生。我基于How to get the time elapsed in C in milliseconds? (Windows)之类的其他问题。但后来我认为,如果第一次调用ftime,结构为time = 1, millitm = 999,而在第二次调用time = 2, millitm = 01时,它将计算经过的时间为1002毫秒。有什么我想念的吗?

各种stackoverflow问题中的建议ftime()和gettimeofday()也被列为已弃用或遗留。

我相信我可以将开始时间转换为毫秒,将检查时间转换为毫秒,然后从检查中减去开始。但是,自纪元以来毫秒需要42位,我试图尽可能高效地保持循环中的所有内容。

我可以采取什么方法来解决这个问题?

2 个答案:

答案 0 :(得分:3)

计算经过时间的代码不正确。

// elapsed += ((check.time - start.time) * 1000)  + (check.millitm - start.millitm);
elapsed = ((check.time - start.time) * (int64_t)1000)  + (check.millitm - start.millitm);

check.millitm - start.millitm存在一些问题。在struct timeb *tp的系统上,可以预期在减法发生之前millitm将被提升为int。因此差异将在[-1000 ... 1000]范围内。

       struct timeb {
           time_t         time;
           unsigned short millitm;
           short          timezone;
           short          dstflag;
       };

IMO,更强大的代码将在单独的辅助函数中处理ms转换。这符合OP的“我相信我可以将开始时间转换为毫秒,将检查时间转换为毫秒,然后从检查中减去开始。”

int64_t timeb_to_ms(struct timeb *t) {
  return (int64_t)t->time * 1000 + t->millitm;
}

struct timeb start, check;
ftime(&start);
int64_t start_ms = timeb_to_ms(&start);

int64_t duration = 10000 /* ms */;
int64_t elapsed = 0;

while (elapsed < duration) {
  // do a set of tasks
  struct timeb check;
  ftime(&check);
  elapsed = timeb_to_ms(&check) - start_ms;
}

答案 1 :(得分:0)

如果您想要效率,请在计时器到期时让系统向您发送信号。

传统上,您可以使用alarm(2)系统调用设置一个分辨率为秒的计时器。

系统然后在计时器到期时向您发送SIGALRM。该信号的默认处置是终止。

如果你处理信号,你可以longjmp(2)从处理程序到另一个地方。

我不认为它比SIGALRM + longjmp更有效率(使用异步计时器,您的代码基本上不受干扰地运行而无需进行任何额外的检查或调用)。

以下是您的示例:

#define _XOPEN_SOURCE
#include <unistd.h>
#include <stdio.h>
#include <signal.h>
#include <setjmp.h>

static jmp_buf jmpbuf;

void hndlr();
void loop();
int main(){

    /*sisv_signal handlers get reset after a signal is caught and handled*/
    if(SIG_ERR==sysv_signal(SIGALRM,hndlr)){
        perror("couldn't set SIGALRM handler");
        return 1;
    }

    /*the handler will jump you back here*/
    setjmp(jmpbuf);

    if(0>alarm(3/*seconds*/)){
        perror("couldn't set alarm");
        return 1;
    }

    loop();

    return 0;
}

void hndlr(){
    puts("Caught SIGALRM");
    puts("RESET");
    longjmp(jmpbuf,1);
}

void loop(){
    int i;
    for(i=0;  ; i++){
        //print each 100-milionth iteration
        if(0==i%100000000){
            printf("%d\n", i);
        }
    }
}

如果alarm(2)不够,您可以使用timer_create(2)作为EOF建议。