PC启动后C#.NET ManualResetEvent的奇怪行为

时间:2015-11-05 11:48:33

标签: c# .net multithreading c#-4.0 manualresetevent

我最近注意到.NET框架中ManualResetEvent类的非常奇怪的行为。我使用的是C#,VS 2015,项目的目标设置为4.5.2。这是完整的代码:

using System;
using System.Diagnostics;
using System.Threading;
using System.Threading.Tasks;

namespace CSharpCOnsole
{
    class Program
    {
        private static ManualResetEvent exit = new ManualResetEvent(false);

        static void Main(string[] args)
        {
            var t = Task.Factory.StartNew(F);
            Console.ReadKey();
            exit.Set();
            t.Wait();
            exit.Close();
        }

        static void F()
        {
            var dtStopwatch = new Stopwatch();
            uint ii = 0;
            while (!exit.WaitOne(25)) {
                dtStopwatch.Stop();
                var dt = 1000.0 * dtStopwatch.ElapsedTicks / Stopwatch.Frequency;
                dtStopwatch.Restart();

                if (ii++ % 40 == 0) {
                    Console.WriteLine(dt.ToString("F3"));
                }
            }
        }
    }
}

我知道这可能听起来很愚蠢,但接下来会发生什么:如果我重新启动电脑,在启动后立即运行VS并运行此程序,我得到以下输出:

31.665
31.365
31.541
...

更重要的是,如果我将25中的!exit.WaitOne(25)更改为范围1631中的任何其他数字,我会得到相同的结果:它等待{{1} }} 女士。如果我选择311范围内的任何数字,它会等待15毫秒。依此类推,如果我选择1632范围内的任何nuber,它会等待47 ms。 但是:如果我编译并运行此代码几次(大约10-30)或等待一段时间(启动后约5-20分钟),它突然开始正常工作!是的,这听起来很荒谬,但事情就是这样。它以1 ms的精度开始以精确的给定时间阻塞循环。它一直持续到下一次PC重启。我在两台不同的PC上试过这个并且得到了相同的行为。谷歌搜索给了我这个问题。如果我在没有VS的情况下运行编译的EXE,我会得到相同的行为。

2 个答案:

答案 0 :(得分:1)

等待任何类型WaitHandle保证等待至少与指定的超时一样长,但可能/可能更长。实际超时由系统时钟和系统繁忙程度决定。如果你想做精确计时WaitHandles或使用它们的类(例如ManualResetEvent)不是要走的路。

答案 1 :(得分:-1)

我找到了答案 - 您可以致电TimeBeginPeriod https://stackoverflow.com/a/15071477/1389883

来设置系统计时器的分辨率

或者您可以使用多媒体计时器API:https://stackoverflow.com/a/24843946/1389883