我最近注意到.NET框架中的ManualResetEvent
类非常奇怪的行为。我正在使用C#,VS 2015,项目的目标设置为4.5.2。下面是完整的代码:PC启动后C#.NET ManualResetEvent的奇怪行为
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
...
更重要的是,如果我在范围16
改变!exit.WaitOne(25)
25
任何其他号码31
,我得到了相同的结果:它等待31
毫秒。如果我选择1
到15
范围内的任何数字,它将精确等待16
毫秒。等等,如果我选择32
到47
范围内的任何标准,它就等于48
毫秒。但是:如果我编译并运行这个代码几次(大约10-30)或者等待一段时间(大约5-20分钟后启动),它突然开始工作正常!是的,这听起来很讽刺,但它会发生什么。它以1 ms的精度开始阻塞精确给定时间的循环。它一直持续到下一台电脑重新启动。我在两台不同的PC上试过这个,并得到相同的行为。谷歌搜索没有给我这个问题绝对没有。如果我运行没有VS的编译EXE,我会得到相同的行为。
听起来像它可能只是其启动并修改某些后台服务某些时点的时钟精度。 –
“它突然开始工作正常”可能有一些其他程序提高了计时器分辨率。 Chrome做了一段时间。消耗电池。 – usr
可能是处理器时间的时间片放置在16ms的时间间隔内,以便在启动时负载过重时在程序执行之间切换。一旦拥有更多的资源,它就能够切换到需要处理时间的程序/线程。您可以检查进程管理器(sysinternals)以查看系统或任务管理器上的负载以获取有关负载的信息。 (我认为编译不是重点,而是编译所需的时间)。一旦负载下降,请检查您是否得到正确的结果。 – Uwe