电脑启动后 C# .NET 手动重置事件的奇怪行为

本文关键字:事件 启动 NET 电脑 | 更新日期: 2023-09-27 18:20:35

我最近注意到ManualResetEvent类在.NET framework中的行为非常奇怪。我正在使用 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"));
                }
            }
        }
    }
}

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

31.665
31.365
31.541
...

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

电脑启动后 C# .NET 手动重置事件的奇怪行为

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

我已经找到了答案 - 您可以通过调用TimeBeginPeriod https://stackoverflow.com/a/15071477/1389883 来设置系统计时器的分辨率

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