当前位置:  开发笔记 > 编程语言 > 正文

如何在Windows上使线程睡眠时间小于一毫秒

如何解决《如何在Windows上使线程睡眠时间小于一毫秒》经验,为你挑选了8个好方法。

在Windows上我遇到了一个我从未在Unix上遇到过的问题.这是如何使线程休眠不到一毫秒.在Unix上,您通常有许多选择(睡眠,睡眠和纳米睡眠)以满足您的需求.但是,在Windows上,只有Sleep具有毫秒级的粒度.

在Unix上,我可以使用select系统调用来创建一个非常简单的微秒睡眠:

int usleep(long usec)
{
    struct timeval tv;
    tv.tv_sec = usec/1000000L;
    tv.tv_usec = usec%1000000L;
    return select(0, 0, 0, 0, &tv);
}

如何在Windows上实现相同的目标?



1> Joel Coehoor..:

这表明对睡眠功能的误解.您传递的参数是睡眠的最短时间.无法保证线程将在指定的时间后唤醒.实际上,线程根本不会"唤醒",而是被调度程序选择执行.调度程序可能会选择等待比请求的睡眠持续时间更长的时间来激活线程,尤其是当另一个线程在此时仍处于活动状态时.


这里有严重的错误信息:"你传递的参数是睡眠的最短时间."**不适用于Windows**:http://msdn.microsoft.com/en-gb/library/windows/desktop/ms686298(v = vs.85).aspx _如果dwMilliseconds小于系统时钟的分辨率,线程可能会睡眠时间少于指定的时间长度.如果dwMilliseconds大于一个tick但小于2,则等待可以是一到两个滴答之间的任何位置,依此类推._
是的,Sleep()只是暗示.根据MSDN,Sleep()时间实际上可以比您请求的时间少*.它只是操作系统的指南,以*任何*粒度提高性能,而不是一个真正好的计时机制.

2> Will Dean..:

正如乔尔所说,你不能在如此短的时间内有意义地"睡觉"(即放弃你的预定CPU).如果你想延迟很短的时间,那么你需要旋转,反复检查一个适当的高分辨率计时器(例如'性能计时器'),并希望高优先级的东西不会先发制人.

如果你真的关心如此短暂的准确延迟,你不应该使用Windows.


原来如此.好吧,如果开发人员或他的用户预见到问题中描述的硬实时要求,那么Windows就不是他们中任何一个应该尝试使用的操作系统.这既不是对Windows的贬义评论,也不是对开发人员傲慢的许可,只是对技术适用性的看法,(作为Windows开发人员:-)我很高兴能够袖手旁观.
-1不考虑应用程序的用户可能有不同的首选项然后开发人员.
不,我指的是“您不应该使用Windows”的说法。开发人员应该为可能需要该程序在Windows中运行的用户制作程序。

3> Joe Schneide..:

使用winmm.lib中提供的高分辨率计时器.请参阅此示例.


我很惊讶这还没有得到更多支持。这是一个真正的解决方案。为什么每个人都赞成“睡眠只是个猜测”而“停止使用Windows,切换到Unix”?我承认了解睡眠只是一种猜测是有帮助的,但这不是解决方案。并不是每个人都可以选择退出Windows。需要明确的是,此解决方案只能使您达到1毫秒的精度(使用媒体库)。那就是我所需要的。我还没有尝试过“选择”技术(由Hendrick&smink发布),但是看起来这可能会使您降低到毫秒级的精度。
@GabeHalsmer链接的代码只能等待1个或多个mSec,这不是要求的内容。而且,它不是开箱即用的编译器,有bug且不是线程安全的,并且可能导致死锁或根本不等待。即使在解决了一些问题后,它仍可以执行预期的工作并要求它等待1毫秒,我也看到它在1到3毫秒的任何地方等待,而这些只是在没有太多负载的系统上的快速测试。因此,它没有比方法更简单的WaitableTimer / WaitForSingleObject组合更好,但更糟,后者至少确实执行了sub-mSec等待。因此:并不是每个人的真正解决方案。

4> 小智..:
#include 

static NTSTATUS(__stdcall *NtDelayExecution)(BOOL Alertable, PLARGE_INTEGER DelayInterval) = (NTSTATUS(__stdcall*)(BOOL, PLARGE_INTEGER)) GetProcAddress(GetModuleHandle("ntdll.dll"), "NtDelayExecution");

static NTSTATUS(__stdcall *ZwSetTimerResolution)(IN ULONG RequestedResolution, IN BOOLEAN Set, OUT PULONG ActualResolution) = (NTSTATUS(__stdcall*)(ULONG, BOOLEAN, PULONG)) GetProcAddress(GetModuleHandle("ntdll.dll"), "ZwSetTimerResolution");




static void SleepShort(float milliseconds) {
    static bool once = true;
    if (once) {
        ULONG actualResolution;
        ZwSetTimerResolution(1, true, &actualResolution);
        once = false;
    }

    LARGE_INTEGER interval;
    interval.QuadPart = -1 * (int)(milliseconds * 10000.0f);
    NtDelayExecution(false, &interval);
}

是的它使用了一些未记录的内核函数,但它运行得很好,我使用SleepShort(0.5); 在我的一些threds



5> darron..:

是的,您需要了解您的操作系统的时间量.在Windows上,除非将时间量更改为1毫秒,否则您甚至不会获得1毫秒的分辨率.(例如使用timeBeginPeriod()/ timeEndPeriod())这仍然不能保证任何东西.即使是一点负载或一个蹩脚的设备驱动程序也会抛弃一切.

SetThreadPriority()有帮助,但非常危险.糟糕的设备驱动程序仍然会毁了你.

你需要一个超控制的计算环境来让这些丑陋的东西工作.


你能解释一下为什么`SetThreadPriority()`很危险吗?

6> user16523..:

如果你想要这么多粒度,你就在错误的地方(用户空间).

请记住,如果您在用户空间,您的时间并不总是精确的.

调度程序可以启动您的线程(或应用程序),并安排它,因此您依赖于OS调度程序.

如果您正在寻找精确的东西,您必须:1)在内核空间(如驱动程序)2)选择RTOS.

无论如何,如果您正在寻找一些粒度(但请记住用户空间的问题),请查看MSDN中的QueryPerformanceCounter函数和QueryPerformanceFrequency函数.



7> mbyrne215..:

正如几位人士指出的那样,睡眠和其他相关功能默认依赖于"系统节拍".这是OS任务之间的最小时间单位; 例如,调度程序的运行速度不会比这更快.即使使用实时操作系统,系统滴答通常也不会小于1毫秒.虽然它是可调的,但这会影响整个系统,而不仅仅是睡眠功能,因为您的调度程序将更频繁地运行,并可能增加操作系统的开销(调度程序运行的时间,相对于任务可以运行的时间).

解决方案是使用外部高速时钟设备.大多数Unix系统都允许您指定定时器和使用的不同时钟,而不是默认的系统时钟.



8> Arno..:

通常,睡眠将至少持续到下一个系统中断发生为止。但是,这取决于多媒体计时器资源的设置。可能将其设置为接近1毫秒,某些硬件甚至允许以0.9765625的中断周期运行(提供的NtQueryTimerResolutionActualResolution将显示0.9766,但这实际上是错误的。他们只是无法将正确的数字输入ActualResolution格式。它为0.9765625毫秒,每秒1024次中断)。

有一个例外可以使我们摆脱以下事实:睡眠时间少于中断时间是不可能的:这是著名的Sleep(0)。这是一个非常强大的工具,使用频率不高!它放弃了线程时间片的提醒。这样,线程将停止,直到调度程序迫使该线程再次获得cpu服务为止。Sleep(0)如果是异步服务,则该调用将强制调度程序独立于中断做出反应。

第二种方法是使用waitable object。诸如等待功能的等待功能WaitForSingleObject()可以等待事件。为了使线程在任何时间(也包括微秒)内处于休眠状态,该线程需要设置一些服务线程,该服务线程将以所需的延迟生成事件。“正在休眠”线程将设置此线程,然后在等待功能处暂停,直到服务线程将设置发出信号的事件为止。

这样,任何线程都可以“休眠”或等待任何时间。服务线程可能非常复杂,并且可能提供系统范围的服务,例如以微秒为单位的定时事件。但是,微秒分辨率可能会迫使服务线程在高分辨率时间服务上旋转最多一个中断周期(〜1ms)。如果注意,它可以很好地运行,尤其是在多处理器或多核系统上。如果仔细处理了调用线程和服务线程的相似性掩码,则在多核系统上旋转1 ms不会造成很大的伤害。

可以在Windows时间戳项目中访问代码,描述和测试。

推荐阅读
wangtao
这个屌丝很懒,什么也没留下!
DevBox开发工具箱 | 专业的在线开发工具网站    京公网安备 11010802040832号  |  京ICP备19059560号-6
Copyright © 1998 - 2020 DevBox.CN. All Rights Reserved devBox.cn 开发工具箱 版权所有