c++, ussleep()已经过时,Windows/MingW的变通方法
c++, usleep() is obsolete, workarounds for Windows/MingW?
我已经发现了另一个问题,Windows/MingW不提供nanosleep()和setitimer()替代过时的ussleep()。但我的目标是修复cppcheck给我的所有警告,包括ussleep()样式警告。
那么,有没有一种方法可以避免在Windows 上使用ussleep()而不使用cygwin或安装新的依赖项/库?谢谢。
我使用的代码来自(最初来自这里):
#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纳秒间隔…正数表示绝对时间. ...负值表示相对时间。"answers"实际的计时器精度取决于硬件的能力。"
如果你有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(对时间字量取模)。我不确定VS.的早期版本
Sleep()
函数的毫秒范围被很好地描述和理解。它不会做任何不可预测的事情。有时,该函数被指责为执行不可预测的操作,即在延迟过期之前返回。我得说这是错的。仔细的调查将证实它的行为是完全可以预测的。唯一的问题是关于它有很多值得一读的地方,而且大部分都是孩子气的。人们也常说windows不是实时操作系统。但这样的评论没有任何贡献,而且是这样评论是用来掩盖知识的缺乏。这让我有点生气,甚至微软注意到了这一点,并提供了更好的文档。
然而,不夸张这个小答案:sleep()函数是精确的,如果使用得当,并且知道它的特点。必须特别注意睡眠(0)。这是一个非常强大的工具,特别是在与进程优先级类、线程优先级、多媒体计时器设置和处理器关联掩码一起使用时。
因此,通常在系统中断期间,真正的睡眠可以轻松安全地执行。当睡眠时间比中断时间短时,需要旋转。为了在更短的时间内旋转,必须使用更高分辨率的时间源。最常见的来源是性能计数器。QueryPerformanceCounter(*arg)
传递一个递增的*参数。QueryPerformanceFrequency(*arg)
提供性能计数器增加的频率。这通常是在MHz范围内,并根据底层硬件而变化。MHz范围内的频率提供微秒级分辨率。这样就可以使用高分辨率的东西来等待所需的时间跨度到期。但是,必须仔细观察其准确性:操作系统将性能计数器频率作为常量返回。这是错误的!由于频率是由物理设备产生的,所以总是有一个偏移,而且它也不是一个常数。它有热漂移。更现代的系统确实有更少的漂移。但如果热漂移仅为1ppm,则误差将为1us/s。偏移量很容易达到100个。1MHz中偏移量100对应100us/s。
如果一个线程需要以高分辨率等待任何时间,它应该建立一个服务线程。两个线程应该共享一个命名事件。服务线程应该在预期的睡眠延迟之前休眠到一个中断周期,然后在剩余的微秒内在性能计数器上旋转。当服务线程到达最终时间时,它设置命名事件并结束。调用线程将被唤醒,因为它正在通过wait函数等待指定的事件。
概要:
- 睡眠被很好地理解,但缺乏记录。
- 服务线程可以在高分辨率下模拟休眠。
- 这样的服务线程可以建立为系统范围的服务。
- 性能计数器的准确性需要仔细观察。需要校准。
更多详细信息可以在Windows时间戳项目
这取决于您需要的粒度。如果你说毫秒,那么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微秒,但你得到1毫秒的睡眠)。如果您想使用第三方库,请使用Boost,但要使用最新版本。与时间相关的std api简直一团糟,我在这里提供一个总结:
- Windows: sleep_for, sleep_until, condition_variable, future等等wait_for/wait_until方法是完全不可靠的,因为它们是基于system_clock的,所以如果时间改变,应用程序可能会挂起。他们在内部解决了这个问题,但由于这是一个ABI中断,他们还没有发布它,甚至在最新的VS 2019上也不可用。
- Linux: sleep_for, sleep_until是可以的,但是condition_variable/future wait_for/wait_until是不可靠的,因为它们也基于系统时钟。
- Boost:与上面相同,但他们修复了1.67版本的时间问题。
因此,如果您想要编写自己的可移植代码或仅使用Boost 1.67+,请不要相信标准的c++11 chrono实现,因为执行的实现非常糟糕。
usleep()
使用微秒。在windows中,为了获得微秒精度,你应该使用QueryPerformanceCounter() winapi函数。在这里你可以找到如何使用它获得精度
- 为不同配置设置MSVC_RUNTIME_LIBRARY的正确方法是什么
- 通过方法访问结构
- 最小硬币更换问题(自上而下方法)
- C++为构建时间获取QDateTime的可靠方法
- 在C#中处理C++指针而不使用unsafe的最佳方法
- 处理多个异常集合的C++方法
- 在VS代码中交叉编译Windows与Linux上的MinGW的SDL程序
- 如果C++类在类方法中具有动态分配,但没有构造函数/析构函数或任何非静态成员,那么它仍然是POD类型吗
- 有什么方法可以遍历结构吗
- 当类在C++中定义时,有什么方法可以"register"类吗?
- 在C++中,将大的无符号浮点数四舍五入为整数的最佳方法是什么
- 实现无开销push_back的最佳方法是什么
- 使用std::函数映射对象方法
- 有符号的int和int-有没有一种方法可以在C++中区分它们
- C++从另一个类访问公共静态向量的正确方法是什么
- C++优先级队列,按对象的唯一指针的特定方法升序排列
- dll中的mingw隐藏方法名称
- MinGW中GetBuffer和ReleaseBuffer的CString方法有哪些替代方案
- 是否有不涉及 I/O 流的 mingw 库原生的就地字符串操作方法
- c++, ussleep()已经过时,Windows/MingW的变通方法