C++ 睡眠的确切时间

C++ 睡眠的确切时间,c++,c,multithreading,real-time,C++,C,Multithreading,Real Time,我对Sleep函数的理解是,它遵循“至少语义”,即Sleep(5)将保证线程睡眠5秒,但根据其他因素,它可能会被阻塞5秒以上。有没有一种方法可以精确地在指定的时间段内睡眠(无需忙着等待)。没有。因为你总是依靠操作系统在正确的时间处理唤醒线程。好吧,你试图解决一个难题,而实现精确的时间安排是不可行的:你能做的最好的事情就是使用,而实现将取决于您的底层硬件和操作系统(即,您将需要,而大多数常规桌面操作系统都不需要)。您的确切目标平台是什么?否 之所以“至少是语义”,是因为在这5秒钟之后,其他线程可能

我对Sleep函数的理解是,它遵循“至少语义”,即Sleep(5)将保证线程睡眠5秒,但根据其他因素,它可能会被阻塞5秒以上。有没有一种方法可以精确地在指定的时间段内睡眠(无需忙着等待)。

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

好吧,你试图解决一个难题,而实现精确的时间安排是不可行的:你能做的最好的事情就是使用,而实现将取决于您的底层硬件和操作系统(即,您将需要,而大多数常规桌面操作系统都不需要)。您的确切目标平台是什么?

之所以“至少是语义”,是因为在这5秒钟之后,其他线程可能会很忙

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

当您将线程置于睡眠状态时,操作系统会将该线程置于等待列表中,当计时器结束时,操作系统会“唤醒”该线程。

这意味着线程将被添加回活动线程列表,但不能保证首先添加t。(如果100个线程需要在那一秒内被唤醒怎么办?谁将首先被唤醒?

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


两者都可以在几毫秒内提供精度。

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

例如,这里有一个例子


这不是一个C问题。

正如其他人所说,您确实需要使用实时操作系统来尝试实现这一点。精确的软件计时是相当棘手的

然而。。。虽然不是完美的,只需提高需要更好时间安排的流程的优先级,就可以获得比“正常”更好的结果。在Windows中,您可以通过该功能实现这一点。如果您将优先级设置为最高级别(
REALTIME\u priority\u CLASS:0x00000100
),您将获得更好的计时结果。再说一遍,这并不像你所要求的那样完美

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

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


一些背景

不久前,我在一个应用程序中使用了
SetPriorityClass
来提高优先级,在这个应用程序中,我对高速视频进行实时分析,一帧也不能错过。帧以每秒300帧(fps)的频率(由外部帧捕获器HW驱动)非常规则地到达pc,这会在我随后服务的每一帧上触发HW中断。由于计时非常重要,我收集了很多关于中断计时的统计数据(使用stuff)来了解情况到底有多糟,并对结果的分布感到震惊。我手头没有统计数据,但基本上Windows在以正常优先级运行时,随时都在为中断提供服务。柱状图非常混乱,stdev比我的~3ms周期宽。在中断服务中,我经常会有200毫秒或更大的间隙(回想一下,中断大约每3毫秒触发一次)!!硬件中断远远不准确!你被操作系统决定为你做的事情困住了

然而,当我发现
实时优先级\u类
设置并用该优先级进行基准测试时,它明显更好,并且服务间隔分布非常紧密。我可以以每秒300帧的速度跑10分钟,而且不会错过任何一帧。测量的中断服务时间几乎完全是1/300秒,分布很紧

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

总之:

  • 如果你真的需要这个,就使用实时操作系统
  • 如果你不能使用实时操作系统(不可能或不切实际),提高进程优先级可能会大大改善你的时间安排,就像我一样
  • 硬件中断不会起作用。。。操作系统仍然需要决定为它们提供服务
  • 确保没有太多其他正在运行的进程在争夺操作系统的注意力
  • 如果时间对你来说真的很重要,做一些测试。尽管让代码在您希望的时候准确地运行不是很容易,但是测量这种偏差是相当容易的。PC中的高性能计数器(通过QueryPerformanceCounter获得的)非常好
  • 因为它可能会有帮助(虽然有点离题),这里有一个我很久以前写的小类,用于在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);
    };
    

    虽然标准Linux不是实时操作系统,但内核开发人员密切关注高优先级进程在保留内核锁的情况下会被饿死多久。因此,对于许多软实时应用程序来说,一个普通的Linux内核通常已经足够好了

    你可以安排你的工作
    #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);
    }