Search code examples
c#.netmultithreadingc#-4.0manualresetevent

Strange behaviour of C# .NET ManualResetEvent after PC startup


I've recently noticed very strange behaviour of ManualResetEvent class in .NET framework. I am using C#, VS 2015, project's target is set to 4.5.2. Here is the full code:

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"));
                }
            }
        }
    }
}

I know that it may sound stupid, but here is what happens: if I restart my PC, run VS right after boot and run this program, i get the following output:

31.665
31.365
31.541
...

What is more, if i change 25 in !exit.WaitOne(25) to any other number in range 16 to 31, i get the same result: it waits 31 ms. If i pick any number in range 1 to 15 it waits exactly 16 ms. And so on, if i pick any nuber in range 32 to 47 it waits exactly 48 ms. BUT: if I compile-and-run this code several times (about 10-30) or wait for some time (about 5-20 min after boot), it suddenly starts working fine! Yes, it sounds ridiculus, but it is what happens. It starts blocking the loop for the exact given time with 1 ms precision. And it keeps going until the next PC restart. I have tried this on two different PCs and got the same behaviour. Googling gave me absolutely nothing on this problem. If i run compiled EXE without VS, i get the same behaviour.


Solution

  • I have found the answer - you can set system timer's resolution by calling TimeBeginPeriod https://stackoverflow.com/a/15071477/1389883

    Or you can use Multimedia Timer API: https://stackoverflow.com/a/24843946/1389883