c ++,usleep()是过时的,Windows / MingW的变通方法?

时间:2011-04-27 09:15:43

标签: c++ windows cppcheck usleep

我已经发现另一个问题,Windows / MingW没有提供过时的usleep()的nanosleep()和setitimer()替代品。 但我的目标是修复cppcheck给我的所有警告,包括usleep()样式警告。

那么,是否有一种解决方法以某种方式避免使用cygwin或安装大量新依赖项/库的Windows 上的usleep()?感谢。

7 个答案:

答案 0 :(得分:44)

我使用了此代码(最初来自here):

#include <windows.h>

void usleep(__int64 usec) 
{ 
    HANDLE timer; 
    LARGE_INTEGER ft; 

    ft.QuadPart = -(10*usec); // Convert to 100 nanosecond interval, negative value indicates relative time

    timer = CreateWaitableTimer(NULL, TRUE, NULL); 
    SetWaitableTimer(timer, &ft, 0, NULL, NULL, 0); 
    WaitForSingleObject(timer, INFINITE); 
    CloseHandle(timer); 
}

请注意,SetWaitableTimer()使用“ 100纳秒间隔...正值表示绝对时间。...负值表示相对时间。”和“实际计时器准确度取决于硬件的功能。

如果你有一个C ++ 11编译器,那么你可以使用this便携版:

#include <chrono>
#include <thread>
...
std::this_thread::sleep_for(std::chrono::microseconds(usec));

感谢Howard Hinnant设计了令人惊叹的<chrono>图书馆(和whose answer below值得更多的爱。)

如果你没有C ++ 11,但是你有提升,那么你可以改为this

#include <boost/thread/thread.hpp>
#include <boost/date_time/posix_time/posix_time.hpp>
...
boost::this_thread::sleep(boost::posix_time::microseconds(usec));

答案 1 :(得分:10)

旧问题的新答案:

新答案的基本原理:工具/操作系统已经更新,现在有一个比最初提出问题时更好的选择。

C ++ 11 <chrono><thread> std标头已经在VS工具集中使用了好几年了。使用这些头文件最好用C ++ 11编写为:

std::this_thread::sleep_for(std::chrono::microseconds(123));

我只使用微秒作为示例持续时间。你可以使用任何恰当的持续时间:

std::this_thread::sleep_for(std::chrono::minutes(2));

使用C ++ 14和一些使用指令,可以更紧凑地编写:

using namespace std::literals;
std::this_thread::sleep_for(2min);

或:

std::this_thread::sleep_for(123us);

这肯定适用于VS-2013(以计时文字为模)。我不确定VS的早期版本。

答案 2 :(得分:8)

Sleep()函数的毫秒范围很好地描述并且很好理解。它没有做任何不可预测的事情。有时,该功能被指责为执行不可预测的,即在延迟到期之前返回。我需要说这是错的。仔细调查将证实其行为是绝对可预测的。唯一的问题是 有很多东西可以阅读它,其中大部分都是带小孩的。人们也经常这样说 Windows它不是一个实时操作系统。但是这样的评论并没有贡献任何东西,而且这样做 评论用于隐藏缺乏知识。这让我有点生气,甚至没有 微软注意到了这一点并提供了更好的文档。

然而,不夸大这个小答案:sleep()函数是精确的,当以正确的方式使用并且知道它的特征时。必须特别注意睡眠(0)。这是一个非常强大的工具,特别是与进程优先级,线程优先级,多媒体计时器设置和处理器关联掩码一起使用时。

因此,通常可以在系统中断期间轻松安全地执行真正的睡眠。当睡眠时间比中断时间短时,需要旋转。 必须在奥德中使用更高分辨率的时间源以在更短的时间内旋转。 最常见的来源是性能计数器。 QueryPerformanceCounter(*arg)提供递增* arg。 QueryPerformanceFrequency(*arg)提供性能计数器递增的频率。这通常在MHz范围内,并且根据底层硬件而变化。 MHz范围内的频率提供微秒分辨率。这样,可以使用高分辨率的某些东西来等待期望的时间跨度到期。但是,必须仔细查看其准确性:OS将性能计数器频率作为常量返回。这是错的!由于生成的频率是物理设备,因此始终存在偏移,也不是a 不变。它有热漂移。更现代的系统确实具有较少的漂移。但如果热漂移仅为1ppm,则误差将为1us / s。偏移可以很容易地为几个100.在1MHz中100的偏移对应于100us / s。

如果一个线程要以高分辨率等待任何时间,它应该建立一个服务线程。两个线程都应共享一个命名事件。服务线程应在所需的睡眠延迟之前休眠1个中断周期,然后在性能计数器上旋转剩余的微秒。当服务线程到达最后时间时,它设置命名事件并结束。调用线程将被唤醒,因为它正在通过等待函数等待命名事件。

要点:

  • 睡眠很好理解,但记录不清。
  • 服务线程可以高分辨率模仿睡眠。
  • 这样的服务线程可以建立为系统范围的服务。
  • 要仔细查看性能计数器的准确性。需要进行校准。

可以在Windows Timestamp Project

找到更详细的信息

答案 3 :(得分:4)

我找到了this blog post about it。它使用QueryPerformanceCounter。功能发布:

#include <windows.h>

void uSleep(int waitTime) {
    __int64 time1 = 0, time2 = 0, freq = 0;

    QueryPerformanceCounter((LARGE_INTEGER *) &time1);
    QueryPerformanceFrequency((LARGE_INTEGER *)&freq);

    do {
        QueryPerformanceCounter((LARGE_INTEGER *) &time2);
    } while((time2-time1) < waitTime);
}

我希望这有点帮助。

答案 4 :(得分:4)

这取决于您需要的粒度。如果您正在谈论毫秒,那么Win32 Sleep功能将完成这项工作 - 请参阅http://msdn.microsoft.com/en-us/library/ms686298%28v=vs.85%29.aspx。如果你正在谈论微秒,那么没有简单的方法可以做到这一点,你很幸运能够在Windows(不是RTOS)或Linux上获得那种计时器分辨率。

答案 5 :(得分:0)

我参加聚会很晚,但是我想在这个问题上添加一些内容。如果要使用微秒分辨率实现可移植性,而不是使用select()系统调用(使用空文件描述符集)来实现可移植性。它可以在linux和Windows上运行,即可以使用统一的界面来调用它(行为可能仍然不同,尤其是在Windows上,您可以请求1微秒但睡眠1毫秒)。如果要使用第三方库,请使用Boost,但要使用最新版本。与时间相关的std api只是一团糟,我在此处提供摘要:

  1. Windows:sleep_for,sleep_until,condition_variable,future等wait_for / wait_until方法是完全不可靠的,因为它们基于system_clock,因此如果时间更改,您的应用程序可能会挂起。他们在内部解决了此问题,但由于是ABI中断,因此尚未发布,即使在最新的VS 2019中也无法使用。
  2. Linux:sleep_for,sleep_until可以,但是condition_variable / future wait_for / wait_until不可靠,因为它们也基于系统时钟。 Gcc 10和GlibC 2.6 bug link已修复该问题。
  3. 提升:与上面相同,但它们解决了1.67版中的时间问题。

因此,如果您要使用可移植的代码编写自己的解决方案或仅使用Boost 1.67+,请不要信任标准实现c ++ 11 chrono,因为执行的实现确实很糟糕。

答案 6 :(得分:-3)

usleep()适用于微秒。在获得微秒精度的窗口中,您应该使用QueryPerformanceCounter() winapi函数。 Here你可以找到如何使用它获得精确度。