Недавно я заметил очень странное поведение класса ManualResetEvent
в .NET framework. Я использую С#, 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)
на любое другое число в диапазоне от 16
до 31
, я получу тот же результат: он ждет 31
мс. Если я выберу любое число в диапазоне от 1
до 15
, оно будет ждать ровно 16
мс. И так далее, если я выберу любое число в диапазоне от 32
до 47
, оно будет ждать ровно 48
мс. НО: если я скомпилирую и запущу этот код несколько раз (около 10-30) или подожду какое-то время (около 5-20 минут после загрузки), он вдруг начнет нормально работать! Да, звучит нелепо, но так бывает. Он начинает блокировать цикл на заданное время с точностью до 1 мс. И так до следующей перезагрузки ПК. Я пробовал это на двух разных ПК и получил такое же поведение. Гугление абсолютно ничего не дало по этой проблеме. Если я запускаю скомпилированный EXE без VS, я получаю такое же поведение.