Linux C ++:时间采样中的“漏洞”

时间:2013-09-11 10:26:21

标签: c++ linux

我有一个运行while(1)循环的线程。在那个循环中,我一直在检查时间,因为我需要在某些时间执行某些任务。 然而,当我将时间打印到屏幕上时,我发现在几秒钟​​内我会得到一个近700毫秒的“洞”。 我尝试设置prcoess优先级:

 policy =  SCHED_FIFO;
 param.sched_priority = 18; 
 if( sched_setscheduler( id, policy, &param ) == -1 ) 
 {
            printf("Error setting scheduler/priority!\n");
  }

以及线程优先级:

pthread_attr_t attr;
struct sched_param param;
pthread_attr_init(&attr);
pthread_attr_setschedpolicy(&attr, SCHED_RR);
param.sched_priority = 50;
pthread_attr_setschedparam(&attr, &param);
    m_INVThreadID  = pthread_create( &m_BaseStationLocatorsThread, &attr,        
                                     ThreadBaseStationLocatorsHandler, (void*) 
                                                                (this));//Linux

但它没有帮助。

我得到时间的方式是:

 struct timespec start;


      clock_gettime( CLOCK_MONOTONIC_RAW, &start);
            //gettimeofday(&tim, NULL);
            //wInitTime = tim.tv_sec*1000 + tim.tv_usec/1000.0;
            double x = start.tv_sec;
            double y = start.tv_nsec;
            x=x*1000;
            y = y/1000000;
            double result = x+ y;
            return result;

或者:

STime   TimeHandler::GetTime()
{
    STime tmpt;
    time_t rawtime;
        tm * timeinfo;
        time(&rawtime);
        timeinfo=localtime(&rawtime);   
        tmpt.day_of_month = timeinfo->tm_mday;
        tmpt.month = timeinfo->tm_mon+1;
        tmpt.year = timeinfo->tm_year+1900;
        tmpt.Hours =  timeinfo->tm_hour;
        tmpt.Min = timeinfo->tm_min;
        tmpt.Sec =  timeinfo->tm_sec;
        tmpt.MilliSeconds = GetCurrentTimeMilliSeconds();
        return tmpt;
}

现在打印时间:

STime timeinfo = GetTime();
    string curTime;
    int datePart; 
    string datePartSTR;
    std::ostringstream convert;

    datePart =timeinfo.day_of_month;
    convert << datePart;
    //curTime.append( convert.str());
    convert << "/";
    datePart = timeinfo.month;
    convert << datePart;
    //curTime.append( convert.str());
        convert << "/";
    datePart =timeinfo.year;
    convert << datePart;
    //curTime.append( convert.str());   

        convert << " ";
        datePart =timeinfo.Hours;
            if (timeinfo.Hours<10)
            convert <<0;
    convert << datePart;
    //curTime.append( convert.str());
        convert << ":";
        datePart =timeinfo.Min;
            if (timeinfo.Min<10)
            convert <<0;
    convert << datePart;
    //curTime.append( convert.str());
        convert << ":";
        datePart =timeinfo.Sec;
        if (timeinfo.Sec<10)
            convert <<0;
    convert << datePart;
        convert << ":";
            datePart =timeinfo.MilliSeconds;
        if (timeinfo.MilliSeconds<100)
                convert << 0;
        if (timeinfo.MilliSeconds<10)
                convert << 0;
    convert << datePart;
    curTime.append( convert.str());


        return curTime;

有什么想法吗?

谢谢!

2 个答案:

答案 0 :(得分:1)

首先,将Cron用于作业调度而不是手动等待循环中的必要时刻然后手动开始工作可能会很好。

根据“时间漏洞”:正如 jdv-Jan de Vaan 在评论中所说,Linux不是实时操作系统(以及Windows和大多数其他面向消费者的操作系统)。鉴于此,您永远无法确定您的线程将在预期的时间片段内以毫秒精度激活。操作系统调度程序,系统活动,甚至CPU限制/节能可能会导致您的应用程序睡眠时间超过一毫秒。因此,不考虑固定时间,最好考虑一些阈值间隔。

答案 1 :(得分:0)

嗯,这可能是一个调度程序延迟问题,但另一方面700mS在现代计算机上是非常长的时间,除非计算机真的超载或动力不足,否则我不会指望那么多调度程序延迟。

另一种可能性是,与用于打印当前时间的逻辑中的错误没有时间间隔。我建议你让你的程序将时空值转换为microseconds-since-epoch,然后让它以该格式打印出已用时间。这样你就可以避免日历日期的变幻莫测。像这样:

uint64_t GetMicrosecondsSinceEpoch()
{
   struct timespec ts;
   if (clock_gettime(CLOCK_MONOTONIC, &ts) != 0) return 0;  // error!
   return (((uint64_t)ts.tv_sec)*1000000) + ((uint64_t)(ts.tv_nsec)/1000)));
}

[...]

static uint64_t prevMicros = 0;
uint64_t nowMicros = GetMicrosecondsSinceEpoch();
int64_t elapsedMicros = nowMicros-prevMicros;
if (prevMicros != 0)
{ 
   printf("Elapsed microseconds since previous time is %lli\n", elapsedMicros);
   if (elapsedMicros >= 500000) printf("ERROR, more than 500mS passed since last time!?\n");
}
prevMicros = nowMicros;

如果上面显示错误,那么它可能是一个调度问题;如果没有,这可能是日期转换问题。

如果您计算要唤醒的每个事件的microseconds-since-epoch值,您可以只取所有这些值中的最小值,从该最小值中减去GetMicrosecondsSinceEpoch()返回的当前值价值,并在那段时间内睡觉......这样你只有在(大约)时间处理下一个事件时才会醒来。这将为您提供更好的时间准确性和更少的CPU /电力使用,而不是定期醒来,只是为了重新入睡。