36

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

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

4

7 回答 7

58

我使用了这段代码(最初来自这里):

#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 编译器,那么你可以使用这个可移植版本:

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

感谢 Howard Hinnant 设计了这个令人惊叹的<chrono>图书馆(下面的答案值得更多的爱。)

如果你没有 C++11,但你有 boost,那么你可以这样

#include <boost/thread/thread.hpp>
#include <boost/date_time/posix_time/posix_time.hpp>
...
boost::this_thread::sleep(boost::posix_time::microseconds(usec));
于 2013-06-24T19:30:47.100 回答
20

旧问题的新答案:

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

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 指令,这可以写得更紧凑一点:

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

或者:

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

这绝对适用于 VS-2013(以 chrono-literals 为模)。我不确定VS的早期版本。

于 2015-08-31T20:09:48.707 回答
11

Sleep()函数的毫秒范围已得到很好的描述和很好的理解。它不会做任何不可预测的事情。有时会指责该函数执行不可预测,即在延迟到期之前返回。我必须说这是错误的。仔细调查将确认它的行为是绝对可预测的。唯一的问题是有很多关于它的阅读,而且大部分都是幼稚的。人们也常说windows它不是一个实时操作系统。但是这样的评论没有任何贡献,而且这样的评论是用来掩饰知识的缺乏。这让我有点生气,甚至微软都没有注意到这一点并提供了更好的文档。

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

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

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

概括:

  • 睡眠是很好理解的,但记录很少。
  • 服务线程可以以高分辨率模拟睡眠。
  • 这样的服务线程可以建立为系统范围的服务。
  • 性能计数器的准确性需要仔细观察。需要校准。

可以在Windows 时间戳项目中找到更多详细信息

于 2012-07-13T12:33:48.273 回答
5

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

于 2011-04-27T09:26:33.280 回答
4

我发现了这篇关于它的博客文章。它使用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);
}

我希望这个能有一点帮助。

于 2011-04-27T09:20:41.010 回答
1

我参加聚会已经很晚了,但我只想为这个问题添加一些内容。如果您想使用微秒分辨率实现可移植性,而不是使用select()使用空文件描述符集的系统调用。它可以在 linux 和 windows 上运行,即可以使用统一的接口调用它(行为可能仍然不同,尤其是在 Windows 上,您可以要求 1 微秒但您会获得 1ms 睡眠)。如果您想使用第三方库,请使用 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错误链接修复
  3. Boost:与上面相同,但他们修复了 1.67 版本的时间问题。

因此,如果您希望可移植代码制作自己的解决方案或仅使用 Boost 1.67+,请不要相信标准实现 c++11 chrono,因为执行的实现非常糟糕。

于 2019-12-29T12:09:39.620 回答
-2

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

于 2011-04-27T09:26:59.700 回答