Почему ManualResetEventSlim.Wait не блокируется в течение полного времени ожидания?
Так что я использую System.Threading.ManualResetEventSlim
в моем коде, и я случайно заметил, что иногда, когда я звоню Wait(TimeSpan)
время ожидания значительно меньше указанного времени.
Вот модульный тест, который демонстрирует мою ситуацию
using System;
using System.Diagnostics;
using NUnit.Framework;
namespace DB
{
[TestFixture]
public class ManualResetEventSlimTests
{
[Test]
[Repeat(100)]
public void TestThatWait_ShouldBlockForAtLeastAsLongAsTheWaitTimeout_IfNotSignalled()
{
TimeSpan waitTime = TimeSpan.FromMilliseconds(250);
using (var waiter = new System.Threading.ManualResetEventSlim(false))
{
var stopwatch = System.Diagnostics.Stopwatch.StartNew();
waiter.Wait(waitTime);
Assert.That(stopwatch.Elapsed, Is.GreaterThanOrEqualTo(waitTime));
}
}
}
}
Этот тест будет проходить большую часть времени, но при повторении 100 раз всегда будет как минимум 1 сбой, поскольку время, измеренное секундомером, меньше указанного времени ожидания. Типичный сбой
Ожидается: больше или равно 00:00:00.2500000 Но было: 00:00:00.2497514
Моей первой мыслью было, что секундомер не достаточно точен, но, похоже, это не так; Stopwatch.Frequency
= 3507511, что означает, что оно должно быть точным до примерно 285 нс на тик, т. Е. Намного, намного меньше, чем расхождение в 0,25 мс (при условии, что оно может точно рассчитывать тики).
Тот факт, что он ожидает на несколько долей мс меньше, чем я ожидал, не влияет на мою конкретную программу, но мне было любопытно, и мой Google-foo не обнаружил ничего уместного. Поэтому я поставил это перед SO-сообществом, чтобы узнать, есть ли у кого-нибудь разумное объяснение.
1 ответ
ManualResetEventSlim
в конечном итоге использует Environment.TickCount
(см. http://referencesource.microsoft.com/#mscorlib/system/threading/ManualResetEventSlim.cs,8a17ba6e95765ed8 и http://referencesource.microsoft.com/#mscorlib/system/threading/SpinWait.cs,9212529427afb371). Документы утверждают:
Обратите внимание, что, поскольку он получен из системного таймера, разрешение свойства TickCount ограничено разрешением системного таймера, которое обычно находится в диапазоне от 10 до 16 миллисекунд.
В качестве таких, Stopwatch
скорее всего будет более точным, чем ManualResetEventSlim
,