C#/.NET定时器和Win32 Sleep函数都不精确

C#/.NET定时器和Win32 Sleep函数都不精确,c#,c++,.net,windows,winforms,C#,C++,.net,Windows,Winforms,对于以下代码: 实际间隔始终为1014.01毫秒,而不是1000毫秒 我还尝试使用C++中的Syt.Word.St.St.Stices、Stult.thordy.Timeand WINAPI睡眠(int)函数,但是总是增加14.01毫秒。 Windows 8的系统时钟是精确的,但Windows API的.NET计时器和睡眠(int)函数都是不精确的 public partial class Form1 : Form { private long ticks; public Fo

对于以下代码:

实际间隔始终为1014.01毫秒,而不是1000毫秒

<>我还尝试使用C++中的Syt.Word.St.St.Stices、Stult.thordy.Timeand WINAPI睡眠(int)函数,但是总是增加14.01毫秒。

Windows 8的系统时钟是精确的,但Windows API的.NET计时器和睡眠(int)函数都是不精确的

public partial class Form1 : Form
{
    private long ticks;

    public Form1()
    {
        InitializeComponent();
    }

    private void Form1_Load(object sender, EventArgs e)
    {
        System.Timers.Timer timer = new System.Timers.Timer(1000);
        // The actual interval is always 1014.01 ms ...
        // I've also tried to use System.Windows.Forms.Timer, System.Threading.Timer
        // and the WinAPI Sleep(int) function in C++, but the additional increase
        // of 14.01 ms always exists.
        timer.Elapsed += timer_Elapsed;
        timer.Start();
        ticks = System.DateTime.Now.Ticks;
    }

    void timer_Elapsed(object sender, System.Timers.ElapsedEventArgs e)
    {
        textBox1.Text = Math.Round((e.SignalTime.Ticks - ticks) / 10000.0, 2).ToString();
        ticks = e.SignalTime.Ticks;
    }
}
更新:

  • 本机睡眠功能(ReactOS):
//使用bAlertable=FALSE调用SleepEx
VOID WINAPI Kernel32.Sleep(以DWORD毫秒为单位)
//使用Alertable=bAlertable调用NtDelayExecution
//和DelayInterval.QuadPart=dwms*-10000
DWORD WINAPI内核32.SleepEx(以DWORD DWM毫秒为单位,以布尔bAlertable为单位)
//syscall存根-直接调用内核模式函数NtDelayExecution
NTSTATUS NTAPI Ntdll.NtDelayExecution(布尔警报格式,PLARGE_整数延迟间隔格式)
//检查DelayInterval的访问权限,然后调用KeDelayExecutionThread
NTSYSCALLAPI NTSTATUS NTAPI Ntoskrnl.NtDelayExecution(布尔警报格式,PLARGE_整数延迟间隔格式)
//睡眠/延迟功能的核心实现
NTKERNELAPI NTSTATUS NTAPI Ntoskrnl.KeDelayExecutionThread(在KPROCESSOR_模式WaitMode中,在布尔警报模式下,
IN-PLARGE_整数间隔(可选)
{
PK定时器;
PKWAIT_块时间块;
PKTHREAD Thread=KeGetCurrentThread();
NTSTATUS-WaitStatus;
布尔可交换;
PLARGE_整数原始时间;
大整数DueTime、NewDueTime、interruptime;
乌龙手=0;
/*如果这是0秒的用户模式等待,则产生执行*/
如果(!(间隔->四部分)&&(等待模式!=KernelMode))
{
/*确保等待未发出警报或未中断APC*/
如果(!(可报警)和(&!(线程->ApcState.UserApcPending))
{
/*屈服执行*/
第二步:去势();
}
}
/*设置原始时间和计时器/等待块*/
原始时间=间隔;
定时器=&线程->定时器;
TimerBlock=&Thread->WaitBlock[TIMER_WAIT_BLOCK];
/*检查锁是否已经锁好*/
如果(!Thread->WaitNext)转到WaitStart;
/*否则,我们已经有了锁,所以初始化等待*/
Thread->WaitNext=FALSE;
KxDelayThreadWait();
/*启动等待循环*/
对于(;;)
{
/*禁用先发制人*/
线程->抢占=FALSE;
/*检查内核APC是否挂起,我们是否低于APC_级别*/
if((线程->ApcState.kernelappending)&&&!(线程->特殊禁用)&&
(线程->WaitIrqlWaitIrql);
}
其他的
{
/*检查我们是否因处于警戒状态而必须救援*/
WaitStatus=KiCheckAlertability(线程、可报警、WaitMode);
如果(WaitStatus!=STATUS\u WAIT\u 0)中断;
/*检查计时器是否过期*/
InterruptTime.QuadPart=KeQueryInterruptTime();
如果((ULONGLONG)interruptime.QuadPart>=计时器->双时间.QuadPart)
{
/*是的,所以我们不需要等待*/
后藤诺瓦特;
}
/*它没有,所以激活它*/
Timer->Header.Inserted=TRUE;
/*处理内核队列*/
if(线程->队列)KiActivateWaiterQueue(线程->队列);
/*设置等待信息*/
线程->状态=等待;
/*将线程添加到等待列表中*/
KiAddThreadToWaitList(线程,可交换);
/*插入计时器并交换线程*/
断言(线程->WaitIrql WaitIrql=KeRaiseIrqlToSynchLevel();
KxDelayThreadWait();
KiAcquireDispatcherLockAtDpcLevel();
}
/*我们完了*/
KiReleaseDispatcherLock(线程->WaitIrql);
返回等待状态;
诺瓦特:
/*没什么可等的了。我们有等待的时间吗*/
如果(!间隔->四部分)
{
/*解锁dispatcher并执行屈服*/
KiReleaseDispatcherLock(线程->WaitIrql);
返回dexecution();
}
/*解锁dispatcher并调整quantum以实现无等待*/
KiReleaseDispatcherLockFromDpcLevel();
KiAdjustQuantumThread(螺纹);
返回状态\成功;
}
//请注意,Windows API睡眠(0)也将调用NtYieldExecution(),请参阅
//上面的函数Ntoskrnl.KeDelayExecutionThread
  • .NET Sleep(1)、Sleep(0)、Yield()和空语句的超时:
(;;)的

{
秒表sw=Stopwatch.StartNew();
//Thread.Sleep(1);//介于36000和39000之间
//Thread.Sleep(0);//2或3
Thread.Yield();//1或2
//空语句//始终为0
控制台写入线(软件ElapsedTicks);
sw.Restart();
}
  • 秒表取决于WinAPI函数QueryPerformanceCounter和QueryPerformanceFrequency:
静态秒表(){
bool successed=SafeNativeMethods.QueryPerformanceFrequency(输出频率);
如果(!成功){
IsHighResolution=false;
频率=滴答声秒;
频率=1;
}
否则{
IsHighResolution=true;
tickFrequency=TicksPerSecond;
频率/=频率;
}
}
公共静态长GetTimestamp(){
如果(IsHighResolution){
长时间戳=0;
SafeNativeMethods.QueryPerformanceCounter(输出时间戳);
返回时间戳;
}
否则{
return DateTime.UtcNow.Ticks;
}
}
  • 秒表是精确的,但DateTime.UtcNow.Ticks和Environment.TickCount都不精确:
//秒表非常精确,没有线。睡眠,总是1000.00毫秒
//但是秒表+线程睡眠(1000)的组合是不精确的
//秒表的螺纹非常精确