System.Diagnostics.Stopwatch returns negative numbers in Elapsed… properties

允我心安 提交于 2019-11-26 17:22:42

问题


Is it normal behaviour that Stopwatch can return negative values? Code sample below can be used to reproduce it.

 while (true)
        {
            Stopwatch sw = new Stopwatch();
            sw.Start();
            sw.Stop();

            if (sw.ElapsedMilliseconds < 0)
                Debugger.Break();

        }

The only place where I can reproduce negative numbers is my virtual machine (hosted by Hyper-V on a 8-core machine)


回答1:


This is a bug. It doesn't seem to have a lot of attention around it, through, so I'd suggesting following up with that report.

The uninspiring workaround appears to be to ignore negative values:

long elapsedMilliseconds = Math.Max(0, stopwatch.ElapsedMilliseconds);



回答2:


I decompiled the Stopwatch class in both .NET 2.0 and .NET 4.0 using Reflector and then compared the differences to see how it was fixed. Besides the addition of the new Restart method, this is all I found for a difference:

public void Stop()
{
    if (this.isRunning)
    {
        long num2 = GetTimestamp() - this.startTimeStamp;
        this.elapsed += num2;
        this.isRunning = false;
// THE NEXT 4 LINES ARE NEW IN .NET 4.0:
        if (this.elapsed < 0L)
        {
            this.elapsed = 0L;
        }
    }
}

So basically they set elapsed to 0 in the Stop method if the value is negative. There are still bugs IMHO:

  1. What if the user reads any of the Elapsed properties before stopping the stopwatch? You might still get a negative value.
  2. Resetting to 0 is not correct. Some time had to have elapsed, even if it was only a few microseconds!
  3. It does nothing to handle the unusually large positive elapsed values that I and others have reported.

EDIT: Unfortunately, #2 and #3 are beyond the power of the .NET Framework:

Here's the core of the problem: from MSDN on QueryPerformanceCounter which is the API used by the Stopwatch class:

On a multiprocessor computer, it should not matter which processor is called. However, you can get different results on different processors due to bugs in the basic input/output system (BIOS) or the hardware abstraction layer (HAL). To specify processor affinity for a thread, use the SetThreadAffinityMask function.

Don't just use .NET 4.0 stopwatch and assume the problem is fixed. It isn't and they can't do anything about it unless you want them to muck with your thread affinity. From the Stopwatch class documentation:

On a multiprocessor computer, it does not matter which processor the thread runs on. However, because of bugs in the BIOS or the Hardware Abstraction Layer (HAL), you can get different timing results on different processors. To specify processor affinity for a thread, use the ProcessThread.ProcessorAffinity method.




回答3:


The "Closed as Fixed" resolution on the Microsoft Connect Bug must mean that they fixed it in .NET 4. I've run the repro code on my desktop and a VM for several minutes and got no negative values.




回答4:


The only workaround that I've found to get the correct elapsed time in a VM is (VB):

Dim tstart AS DateTime = Now
...executing code...
Dim telapsed = (Now - tstart).TotalMilliseconds


来源:https://stackoverflow.com/questions/1008345/system-diagnostics-stopwatch-returns-negative-numbers-in-elapsed-properties

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!