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

blu*_*rnd 24 c++ windows cppcheck usleep

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

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

Adi*_*vit 46

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

#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); 
}
Run Code Online (Sandbox Code Playgroud)

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

如果你有一个C++ 11编译器,那么你可以使用这个可移植版本:

#include <chrono>
#include <thread>
...
std::this_thread::sleep_for(std::chrono::microseconds(usec));
Run Code Online (Sandbox Code Playgroud)

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

如果你没有C++ 11,但你有提升,那么你可以做这个,而不是:

#include <boost/thread/thread.hpp>
#include <boost/date_time/posix_time/posix_time.hpp>
...
boost::this_thread::sleep(boost::posix_time::microseconds(usec));
Run Code Online (Sandbox Code Playgroud)


How*_*ant 13

旧问题的新答案:

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

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

std::this_thread::sleep_for(std::chrono::microseconds(123));
Run Code Online (Sandbox Code Playgroud)

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

std::this_thread::sleep_for(std::chrono::minutes(2));
Run Code Online (Sandbox Code Playgroud)

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

using namespace std::literals;
std::this_thread::sleep_for(2min);
Run Code Online (Sandbox Code Playgroud)

要么:

std::this_thread::sleep_for(123us);
Run Code Online (Sandbox Code Playgroud)

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

  • 就在前几天,我在一个简单的测试程序中遇到了仅限 Windows 的死锁,该程序使用 sleep_for 等待几微秒。MS 的实现似乎可以归结为睡眠(或等效的),这需要几毫秒。调用 sleep_for 时间少于一毫秒将转换为 Sleep(0)。Sleep() 文档解释说,在某些情况下从线程池线程调用 Sleep(0) 可能会导致死锁,而这些情况在我们的测试套件中很常见。以毫秒调用 sleep_for 解决了问题。 (3认同)

Arn*_*rno 8

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

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

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

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

摘要:

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

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


orl*_*rlp 5

我找到了关于此的博客文章。它使用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);
}
Run Code Online (Sandbox Code Playgroud)

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

  • 这是一个繁忙的等待。这会浪费CPU周期。 (6认同)
  • @tibor是的。据我所知,Windows进程调度程序不提供任何微秒级的睡眠过程。但是,您可以创建混合睡眠功能,使用默认的睡眠功能(以毫秒为单位),然后使用忙碌等待最后一个小的等待时间。这样可以在不牺牲精度的情况下将性能下降降低到忙碌等待时间少于5 ms。 (6认同)
  • 当前代码忽略了“ freq”的值。相反,如果waitTime以微秒为单位,则最终测试应为“ time2-time1 &lt;waitTime * freq / 1000000”。 (4认同)

小智 5

这取决于您需要的粒度。如果您说的是毫秒,则Win32 Sleep函数将完成此任务-请参见http://msdn.microsoft.com/zh-cn/library/ms686298%28v=vs.85%29.aspx。如果您正在谈论微秒,那么没有简单的方法可以做到,而您将很幸运在Windows(不是RTOS)或Linux上获得这种计时器分辨率。


Mih*_*yan -2

usleep()以微秒为单位。在 Windows 中,要获得微秒精度,您应该使用QueryPerformanceCounter() winapi 函数。在这里您可以找到如何使用它来获得该精度。

  • 虽然 QueryPerformanceCounter 可以提供高分辨率时钟值,但它不是实时休眠 API——它只能让您忙等待。 (5认同)
  • Windows 中没有什么是“实时的”。对于微秒或纳秒范围内的值,睡眠不是一个概念。Windows 调度程序使用大约 10 毫秒的量子。除非您经常这样做,否则微秒级的繁忙等待并不可怕。 (2认同)