我已经发现另一个问题是 Windows/MingW 没有提供 nanosleep() 和 setitimer() 替代过时的 usleep()。但我的目标是修复 cppcheck 给我的所有警告,包括 usleep() 样式的警告。
那么,是否有一种解决方法可以在不使用 cygwin 或安装大量新依赖项/库的情况下以某种方式避免 Windows 上的 usleep() ?谢谢。
我使用了这段代码(最初来自这里):
#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));
旧问题的新答案:
新答案的理由:工具/操作系统已经更新,现在有比最初提出问题时更好的选择。
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的早期版本。
该Sleep()
函数的毫秒范围已得到很好的描述和很好的理解。它不会做任何不可预测的事情。有时会指责该函数执行不可预测,即在延迟到期之前返回。我必须说这是错误的。仔细调查将确认它的行为是绝对可预测的。唯一的问题是有很多关于它的阅读,而且大部分都是幼稚的。人们也常说windows它不是一个实时操作系统。但是这样的评论没有任何贡献,而且这样的评论是用来掩饰知识的缺乏。这让我有点生气,甚至微软都没有注意到这一点并提供了更好的文档。
然而,不要夸大这个小答案:当以正确的方式使用并且知道它的特性时,sleep() 函数是精确的。必须特别注意 sleep(0)。这是一个非常强大的工具,特别是与进程优先级、线程优先级、多媒体计时器设置和处理器关联掩码一起使用时。
因此,在系统中断期间,通常可以轻松安全地执行真正的睡眠。当涉及比中断周期短的睡眠时,需要旋转。为了在更短的时间内旋转,必须使用更高分辨率的时间源。最常见的来源是性能计数器。QueryPerformanceCounter(*arg)
提供一个递增的 *arg。QueryPerformanceFrequency(*arg)
提供性能计数器递增的频率。这通常在 MHz 范围内,并且根据底层硬件而有所不同。MHz 范围内的频率提供微秒级分辨率。这种方式可以使用高分辨率的东西来等待所需的时间跨度到期。但是,必须仔细检查其准确性:操作系统将性能计数器频率作为常数返回。这是错误的!由于频率是由物理设备生成的,因此始终存在偏移,也不是常数。它有热漂移。更现代的系统确实有更少的漂移。但如果热漂移仅为 1ppm,则误差为 1us/s。偏移量可以轻松达到几个 100。1MHz 中的 100 偏移量对应于 100us/s。
如果一个线程要等待高分辨率的任何时间,它应该建立一个服务线程。两个线程应共享一个命名事件。服务线程应在所需的休眠延迟之前休眠 1 个中断周期,然后在剩余的微秒内在性能计数器上旋转。当服务线程到达最终时间时,它设置命名事件并结束。调用线程将被唤醒,因为它正在通过等待函数等待指定事件。
概括:
这取决于您需要什么粒度。如果您说的是毫秒,那么 Win32 睡眠功能将完成这项工作 - 请参阅http://msdn.microsoft.com/en-us/library/ms686298%28v=vs.85%29.aspx。如果您说的是微秒,那么就没有简单的方法可以做到这一点,您很幸运能够在 Windows(不是 RTOS)或 Linux 上获得这种计时器分辨率。
我发现了这篇关于它的博客文章。它使用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);
}
我希望这个能有一点帮助。
我参加聚会已经很晚了,但我只想为这个问题添加一些内容。如果您想使用微秒分辨率实现可移植性,而不是使用select()
使用空文件描述符集的系统调用。它可以在 linux 和 windows 上运行,即可以使用统一的接口调用它(行为可能仍然不同,尤其是在 Windows 上,您可以要求 1 微秒但您会获得 1ms 睡眠)。如果您想使用第三方库,请使用 Boost,但要使用最新版本。与时间相关的 std api 只是一团糟,我在这里提供一个摘要:
因此,如果您希望可移植代码制作自己的解决方案或仅使用 Boost 1.67+,请不要相信标准实现 c++11 chrono,因为执行的实现非常糟糕。
usleep()
适用于微秒。在获得微秒精度的窗口中,您应该使用QueryPerformanceCounter() winapi 函数。在这里您可以找到如何使用它来获得该精度。