【问题标题】:Program stops unexpectedly when I use gettimeofday() in an infinite loop当我在无限循环中使用 gettimeofday() 时程序意外停止
【发布时间】:2017-09-25 08:02:00
【问题描述】:

我编写了一个代码来确保 while(1) 循环的每个循环都花费特定的时间(在本例中为 10000µS,等于 0.01 秒)。问题是这段代码在开始时运行良好,但不到一分钟就停止了。就像访问linux时间有限制一样。现在,我正在初始化一个布尔变量,以使这个时间计算运行一次而不是无限。由于性能随时间而变化,因此最好计算每个循环的计算时间。有没有其他方法可以做到这一点?

void some_function(){
struct timeval tstart,tend;
while (1){
   gettimeofday (&tstart, NULL);
   ...
   Some computation
   ...
   gettimeofday (&tend, NULL);
   diff = (tend.tv_sec - tstart.tv_sec)*1000000L+(tend.tv_usec - tstart.tv_usec);
   usleep(10000-diff);
   }
}

【问题讨论】:

  • 停止时有没有提示信息?
  • 检查diff是否溢出。
  • diff 大于 10000 时会发生什么?即使你的计算总是少于 10000us 并不意味着系统会一直运行它。在将控制权交还给您的程序之前,系统可能会选择运行其他进程相当长的一段时间。所以你很容易得到 diff 远大于 10000。使用挂钟进行计时并不总是一个好主意。 (如果你想知道会发生什么,usleep 的参数通常是一个无符号数)。
  • 添加一些调试printf 调用。
  • @venth1a 你确定它是永远的吗?你测试了吗?我很确定这不会是永远的,而是大约 71 分钟。

标签: c linux gettimeofday


【解决方案1】:

来自 usleep 的手册页

 #include <unistd.h>

 int usleep(useconds_t usec);

usec 是 unsigned int,现在猜猜下面一行中 diff 大于 10000 时会发生什么

 usleep(10000-diff);

【讨论】:

    【解决方案2】:

    嗯,你为得到差异所做的计算是错误的:

    diff = (tend.tv_sec - tstart.tv_sec)*1000000L+(tend.tv_usec - tstart.tv_usec);
    

    您正在混合不同的整数类型,缺少 tv_usec 可以是 unsigned 数量,您正在从另一个 unsigned 中减去它并且可能溢出....之后,您会得到整整一秒4.0E09usec 左右的数量。这是大约 4000 秒。或一个多小时……大约。最好检查是否有进位,在这种情况下,增加tv_sec,然后从tv_usec 中减去10000000 以获得适当的正值。

    我不知道您为struct timeval 使用的实现,但最有可能的是tv_sectime_t(甚至可以是64 位)而tv_usec 通常只是unsigned 32位值,因为它不会远离1000000

    让我举例说明...假设您已经用了 100 毫秒进行计算...而这恰好发生在一秒钟的中间...您有

    tstart.tv_sec = 123456789; tstart.tv_usec = 123456;
    tend.tv_sec = 123456789; tend.tv_usec = 223456;  
    

    当你减去时,它会导致:

    tv_sec = 0; tv_usec = 100000;
    

    但假设您在第二个更改时完成了计算

    tstart.tv_sec = 123456789; tstart.tv_usec = 923456;
    tend.tv_sec =  123456790; tend.tv_usec = 23456;
    

    时间差又是 100 毫秒,但是现在,当你计算你的表达式时,你得到的第一部分是 1000000(整整一秒),但是在减去第二部分之后,你会得到 23456 - 923456 =*=&gt; 4294067296 (*) 和溢出. 所以您可以访问usleep(4295067296)4295s.1h 11m 更多。 我认为您没有足够的耐心等待它完成...但这可能会发生在您的程序中,具体取决于 struct timeval 的定义方式。

    进行进位工作的正确方法是重新排序总和以先进行所有加法,然后再进行减法。这会在同时处理 signedunsigned 时强制转换为有符号整数,并防止 unsigneds 中的负溢出。

    diff = (tend.tv_sec - tstart.tv_sec) * 1000000 + tstart.tv_usec - tend.tv_usec;
    

    解析为

    diff = (((tend.tv_sec - tstart.tv_sec) * 1000000) + tstart.tv_usec) - tend.tv_usec;
    

    【讨论】:

      猜你喜欢
      • 2015-03-22
      • 2015-02-07
      • 1970-01-01
      • 1970-01-01
      • 2023-01-13
      • 2018-09-07
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多