睡觉一段确切的时间

时间:2011-03-06 08:07:44

标签: c++ c multithreading real-time

我对睡眠功能的理解是它遵循“至少语义”,即睡眠(5)将保证线程休眠5秒,但是根据其他因素,它可能会保持阻塞超过5秒。有没有办法在指定的时间段内睡觉(没有忙碌等待)。

7 个答案:

答案 0 :(得分:14)

正如其他人所说,你真的需要使用实时操作系统来尝试实现这一目标。精确的软件定时非常棘手。

然而......虽然并不完美,但通过简单地提高需要更好时间的流程的优先级,您可以获得比“正常”更好的结果。在Windows中,您可以使用SetPriorityClass功能实现此目的。如果您将优先级设置为最高级别(REALTIME_PRIORITY_CLASS: 0x00000100),您将获得更多更好的计时结果。再次 - 这不会像你要求的那样完美。

在Windows以外的其他平台上也可能这样做,但我从来没有理由这样做,所以没有测试过。

编辑:根据Andy T的评论,如果您的应用程序是多线程的,您还需要注意分配给线程的优先级。对于Windows,这是记录here


一些背景......

前段时间我使用SetPriorityClass来提升我正在对高速视频进行实时分析的应用程序的优先级,我不会错过任何一帧。帧以#em>非常常规(由外部帧抓取器硬件驱动)频率以每秒300帧(fps)的速度到达计算机,这会在我接下来服务的每一帧上发出一个HW中断。由于时间非常重要,我收集了很多关于中断时间的统计数据(使用QueryPerformanceCounter的东西),看看情况有多糟糕,并对结果发行版感到震惊。我没有方便的统计数据,但基本上Windows正在服务中断,只要它在正常优先级运行时感觉它。直方图非常混乱,stdev比我的约3ms时间宽。在中断服务中经常会有200 ms或更大的巨大间隙(回想一下中断大约每3 ms发出一次)!即:硬件中断是确切的FAR!你坚持操作系统决定为你做的事情。

然而 - 当我发现REALTIME_PRIORITY_CLASS设置并使用该优先级进行基准测试时,显着更好,服务间隔分布非常紧张。我可以运行10分钟300 fps而不会错过任何一帧。测量的中断服务周期几乎完全是1/300秒,分布很紧密。

此外 - 尝试并尽量减少操作系统正在做的其他事情,以帮助提高您的计划在应用程序中更好地工作的几率。例如:当你试图用其他代码获得精确计时时,没有背景视频转码或磁盘去碎片或任何东西!!

总结:

  1. 如果你真的需要这个,请使用实时操作系统
  2. 如果您不能使用实时操作系统(不可能或不切实际),提高您的流程优先级可能会大大改善您的时间安排,就像它对我一样。
  3. 硬件中断不会这样做......操作系统仍然需要决定为它们提供服务!
  4. 确保您没有运行许多正在竞争操作系统注意的其他进程
  5. 如果时间对您来说非常重要,请进行一些测试。虽然在需要时获取运行正好的代码并不容易,但测量这种偏差非常容易。 PC中的高性能计数器(你使用QueryPerformanceCounter得到的)非常好。
  6. 因为它可能会有所帮助(虽然有点偏离主题),这是我很久以前写的一个小类,用于在Windows机器上使用高性能计数器。它可能对您的测试有用:

    <强> CHiResTimer.h

    #pragma once
    #include "stdafx.h"
    #include <windows.h>
    
    class CHiResTimer
    {
    private:
        LARGE_INTEGER frequency;
        LARGE_INTEGER startCounts;
        double ConvertCountsToSeconds(LONGLONG Counts);
    public:
        CHiResTimer(); // constructor
        void ResetTimer(void);
        double GetElapsedTime_s(void);
    };
    

    <强> CHiResTimer.cpp

    #include "stdafx.h"
    #include "CHiResTimer.h"
    
    double CHiResTimer::ConvertCountsToSeconds(LONGLONG Counts)
    {
        return ((double)Counts / (double)frequency.QuadPart) ;
    }
    
    CHiResTimer::CHiResTimer()
    {
        QueryPerformanceFrequency(&frequency);
        QueryPerformanceCounter(&startCounts); // starts the timer right away
    }
    
    void CHiResTimer::ResetTimer()
    {
        QueryPerformanceCounter(&startCounts); // reset the reference counter
    }
    
    double CHiResTimer::GetElapsedTime_s()
    {
        LARGE_INTEGER countsNow;
        QueryPerformanceCounter(&countsNow);
        return ConvertCountsToSeconds(countsNow.QuadPart - startCounts.QuadPart);
    }
    

答案 1 :(得分:5)

没有

它至少是“语义”的原因是因为在那5秒之后,其他一些线程可能会忙。

每个线程都从操作系统获取时间片。操作系统控制线程的运行顺序。

当你让线程进入休眠状态时,操作系统会将线程置于等待列表中,当计时器结束时,操作系统会“唤醒”该线程。
这意味着线程被添加回活动线程列表,但不保证首先添加t。 (如果在特定的第二个线程中需要唤醒100个线程怎么办?谁先走?)

答案 2 :(得分:4)

虽然标准Linux不是实时操作系统,但内核开发人员密切关注高优先级进程在保持内核锁定时会持续多久。因此,对于许多软实时应用程序来说,库存Linux内核通常都足够好。

您可以使用sched_setscheduler(2)SCHED_FIFO通过SCHED_RR调用将您的流程安排为实时任务。两者在语义上略有不同,但可能足以知道SCHED_RR任务最终会由于时间片而将处理器放弃到具有相同优先级的另一个任务,而SCHED_FIFO任务只会由于阻止I / O或显式调用sched_yield(2),将CPU放弃到具有相同优先级的另一个任务。

使用实时计划任务时要小心;因为它们始终优先于标准任务,所以您可以轻松地找到自己编码的无限循环,从而不会放弃CPU并阻止管理员使用ssh来终止进程。因此,以更高的实时优先级运行sshd可能没什么坏处,至少在您确定已修复最严重的错误之前。

已经有一些Linux可用的变种可以提供硬实时保证。 RTLinuxcommercial support; XenomaiRTAI是针对Linux的实时扩展的竞争实现,但我对它们一无所知。

答案 3 :(得分:2)

好吧,你试图解决一个难题,并且实现完全时间是不可行的:你能做的最好是使用hardware interrupts,实现将取决于您的底层硬件和您的操作系统(即,您将需要a real-time operating system,大多数常规桌面操作系统都不需要)。您的确切目标平台是什么?

答案 4 :(得分:2)

正如之前的回答者所说:没有办法确切(一些建议的实时操作系统或硬件中断,甚至那些完全)。我认为你所寻找的东西比sleep()函数更精确,你会发现这取决于你的操作系统,例如: Windows Sleep()函数或GNU下的nanosleep()函数。

  

http://msdn.microsoft.com/en-us/library/ms686298%28VS.85%29.aspx

     

http://www.delorie.com/gnu/docs/glibc/libc_445.html

两者都会在几毫秒内给你精确度。

答案 5 :(得分:0)

没有。因为你总是依赖操作系统来处理在正确的时间唤醒线程。

答案 6 :(得分:0)

使用标准C无法在指定的时间段内睡眠。您至少需要一个提供更大粒度的第三方库,您可能还需要一个特殊的操作系统内核,例如实时Linux内核。

例如,这是一个discussion of how close you can come on Win32 systems

这不是C问题。