Подтвердить что ты не робот

System.Diagnostics.Stopwatch возвращает отрицательные числа в свойствах Elapsed...

Является ли обычное поведение тем, что секундомер может возвращать отрицательные значения? Пример кода, приведенный ниже, можно использовать для его воспроизведения.

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

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

        }

Единственное место, где я могу воспроизвести отрицательные числа, - это моя виртуальная машина (размещенная Hyper-V на 8-ядерном компьютере)

4b9b3361

Ответ 2

Я декомпилировал класс 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 в методе Стоп, если значение отрицательное. Есть еще ошибки IMHO:

  • Что делать, если пользователь читает любое из свойств Elapsed перед остановкой секундомера? Вы все равно можете получить отрицательное значение.
  • Сброс в 0 неверен. Некоторое время должно было пройти, даже если было всего несколько микросекунд!
  • Он ничего не делает для обработки необычно больших положительных истекших значений, о которых я и другие сообщали.

EDIT: К сожалению, # 2 и # 3 выходят за рамки .NET Framework:

Здесь ядро ​​проблемы: от MSDN на QueryPerformanceCounter, который является API, используемым классом секундомера:

На многопроцессорном компьютере не должно иметь значения, какой процессор называется. Тем не менее, вы можете получить разные результаты по разным процессоров из-за ошибок в базовой системе ввода/вывода (BIOS) или уровень абстракции аппаратного обеспечения (HAL). Чтобы указать сродство процессора к thread, используйте функцию SetThreadAffinityMask.

Не просто использовать секундомер .NET 4.0 и предполагать, что проблема исправлена. Это не так, и они ничего не могут с этим поделать, если вы не хотите, чтобы они гадали с вашей ниточкой. Из документации класса секундомера:

На многопроцессорном компьютере не имеет значения, какой процессор поток работает. Однако из-за ошибок в BIOS или аппаратном обеспечении Уровень абстракции (HAL), вы можете получить разные результаты синхронизации по разные процессоры. Чтобы указать сродство процессора к потоку, используйте метод ProcessThread.ProcessorAffinity.

Ответ 3

Разрешение "Закрыто как фиксированное" на Ошибка Microsoft Connect означает, что они исправили его в .NET 4. Я запустил воспроизведите код на моем рабочем столе и виртуальную машину в течение нескольких минут и не получите отрицательных значений.

Ответ 4

Единственным обходным решением, которое я нашел, чтобы получить правильное истекшее время в VM, является (VB):

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