是否在线程上下文切换时更新了低分辨率的Windows时钟

时间:2013-10-31 17:50:23

标签: windows multithreading timer

几年前,我注意到.Net DateTime类只是以大约10到15毫秒的增量变化。这恰好与我理解的是Windows中线程上下文的典型持续时间一致(这就是为什么线程永远不会睡眠的时间少于那个)。暴露在那里的低分辨率窗口时钟是否真的在线程上下文切换时精确更新?它们可以用作检测上下文切换的廉价和脏的方法吗?

2 个答案:

答案 0 :(得分:3)

事实上,我会给出一个实际答案:

那里暴露的低分辨率窗口时钟是否真的在线程上下文切换时精确更新了?

不 - 你已经倒退了。低分辨率Windows时钟可能会导致上下文变化,例如。如果API调用超时超时,或者Sleep()调用过期。

它们可以用作检测上下文切换的廉价和脏的方法吗?

不,因为上下文切换可能不会在每个定时器中断发生,并且经常发生在所有其他硬件中断和API调用上。

答案 1 :(得分:2)

你做了几个无效或至少是无根据的假设。

首先,您假设更新DateTime.Now的15 ms的.NET限制是Windows限制。它可能是,但它可能不是。

您假设Thread.Sleep()的分辨率与DateTime.Now有某种关联。不是。您还假设15 ms的最小睡眠是Windows限制。事实并非如此。

此外,本声明的最后部分:

  

这恰好与我理解的是Windows中线程上下文的典型持续时间一致(这就是为什么线程永远不会以低于该值的方式睡眠的原因)。

完全是假的。线程可以放弃其时间片的剩余部分,这意味着可以安排另一个线程在该时间段内执行。即使在.NET程序中,线程也可以休眠不到15毫秒。

更重要的是,DateTime.Now和用于进行上下文切换的机制几乎完全不相关。 DateTime.Now返回的值有可能甚至没有更新,除非您要求它,就像Stopwatch类没有保持Elapsed字段一样,但是而是计算你问的时间。

所以,不,不可能使用时钟来检测上下文切换。

事实证明,DateTime.Now分辨率为15毫秒的神话是错误的。该计划表明:

        var results = new List<double>();
        var startTime = DateTime.Now;
        var endTime = startTime.AddSeconds(10);
        var lastTime = startTime;
        var nowTime = startTime;
        while (nowTime < endTime)
        {
            nowTime = DateTime.Now;
            if (nowTime != lastTime)
            {
                results.Add((nowTime - lastTime).TotalMilliseconds);
                lastTime = nowTime;
            }
        }
        Console.WriteLine("Total changes = {0}", results.Count);
        var avg = results.Average();
        var min = results.Min();
        var max = results.Max();
        Console.WriteLine("Min: {0},  Max: {1},  Avg: {2}", min, max, avg);

该程序在紧密循环中检查DateTime.Now 10秒钟,并在返回值发生变化时将一个项目添加到列表中。对我来说典型的运行导致输出非常类似于:

Total changes = 9980
Min: 0.9999,  Max: 19.998,  Avg: 1.00210418837676

因此它在10,000毫秒内完成了9,980次更新。它看起来好像只有一次没有每毫秒更新一次。那可能是因为在那段时间内线程被换掉了。

我常常得到:

Total changes = 10000
Min: 1,  Max: 1,  Avg: 1

这意味着时钟每毫秒更新一次。