Я декомпилировал класс Stopwatch в .NET 2.0 и .NET 4.0 с помощью Reflector, а затем сравнил различия, чтобы увидеть, как это было исправлено. Помимо добавления нового метода Restart, это все, что я нашел для разницы:
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;
}
}
}
Таким образом, они устанавливают значение 0 в методе Stop, если значение отрицательное. Есть еще баги ИМХО:
- Что если пользователь прочитает какое-либо из свойств Elapsed перед остановкой секундомера? Вы все еще можете получить отрицательное значение.
- Сброс на 0 неверен. Некоторое время должно было пройти, даже если это было всего несколько микросекунд!
- Он ничего не делает для обработки необычно больших положительных прошедших значений, о которых я и другие сообщили.
РЕДАКТИРОВАТЬ: К сожалению, # 2 и # 3 находятся за пределами возможностей .NET Framework:
Вот суть проблемы: из MSDN на QueryPerformanceCounter , который представляет собой API, используемый классом секундомера:
На многопроцессорном компьютере не должно иметь значения, какой процессор
называется. Тем не менее, вы можете получить разные результаты на разных
процессоры из-за ошибок в базовой системе ввода / вывода (BIOS) или
уровень аппаратной абстракции (HAL). Чтобы указать сродство процессора для
поток, используйте функцию SetThreadAffinityMask.
Не просто используйте секундомер .NET 4.0 и предположите, что проблема исправлена. Это не так, и они ничего не могут с этим поделать, если вы не хотите, чтобы они испортили вашу привязанность к нитям. Из документации класса Секундомер:
На многопроцессорном компьютере не имеет значения, какой процессор
поток работает. Однако из-за ошибок в BIOS или оборудовании
Слой абстракции (HAL), вы можете получить различные результаты синхронизации на
разные процессоры. Чтобы указать привязку процессора к потоку, используйте
метод ProcessThread.ProcessorAffinity.