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:
- What if the user reads any of the Elapsed properties before stopping the stopwatch? You might still get a negative value.
- Resetting to 0 is not correct. Some time had to have elapsed, even if it was only a few microseconds!
- 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.