So I am using System.Threading.ManualResetEventSlim
in my code and I happened to notice that sometimes when I call Wait(TimeSpan)
the time spent waiting is significantly less than the time specified.
Here is a unit test that demonstrates my situation
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));
}
}
}
}
This test will pass most of the time but when repeated 100 times there is always at least 1 failure because the time measured by the stopwatch is less than the specified wait TimeSpan. A typical failure is
Expected: greater than or equal to 00:00:00.2500000 But was: 00:00:00.2497514
My first thought was that the stopwatch was not accurate enough but that appears not to be the case; the Stopwatch.Frequency
= 3507511, which means that it should be accurate to something like 285ns per tick i.e. much, much less than the discrepancy of 0.25ms (assuming that it can accurately count ticks).
The fact that it waits a few fractions of a ms less than I expected does not have any impact on my particular program but I was curious and my Google-foo did not uncover anything relevant. So I put it to the SO community to see if someone has a reasonable explanation.
ManualResetEventSlim
ultimately uses Environment.TickCount
(see http://referencesource.microsoft.com/#mscorlib/system/threading/ManualResetEventSlim.cs,8a17ba6e95765ed8 and http://referencesource.microsoft.com/#mscorlib/system/threading/SpinWait.cs,9212529427afb371) . The docs state:
Note that, because it is derived from the system timer, the resolution of the TickCount property is limited to the resolution of the system timer, which is typically in the range of 10 to 16 milliseconds
As such, Stopwatch
is likely being more accurate / precise than ManualResetEventSlim
.