Что происходит, когда GetTickCount () переносится?

Если поток делает что-то вроде этого:

const DWORD interval = 20000;
DWORD ticks = GetTickCount();
while(true)
{
    DoTasksThatTakeVariableTime();

    if( GetTickCount() - ticks > interval )
    {
        DoIntervalTasks();
        ticks = GetTickCount();
    }
}

В конечном счете, галочки собирается перенестись, когда значение не помещается в DWORD.

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

Кто прав, и почему?

Спасибо.

14
задан Scott Langham 7 April 2009 в 23:10
поделиться

8 ответов

Из документов:

Прошедшее время хранится как значение DWORD. Поэтому время повторится, чтобы обнулить, если система будет выполняться непрерывно в течение 49,7 дней. Для предотвращения этой проблемы используйте GetTickCount64. Иначе проверьте на водосливное условие при сравнении времен.

Однако DWORD не подписан - таким образом, необходимо быть хорошо. 0 - "очень большое количество" = "небольшое число" (принимающий Вас не имеют никакой проверки переполнения активной, конечно). У меня было предыдущее редактирование, которое предположило, что Вы получите отрицательное число, но это было, прежде чем я принял во внимание, что DWORD не подписан.

У Вас все еще будет проблема, если операция займет чуть менее чем 49,7 дней все же. Это не может быть проблемой для Вас ;)

Один способ протестировать состоял бы в том, чтобы погасить GetTickCount() метод, таким образом, Вы могли записать модульные тесты, где Вы явно заставляете его перенестись. С другой стороны, если Вы действительно только сомневаетесь относительно арифметической части, можно легко записать модульные тесты на это :) Действительно, то, что число прибывает из системных часов, в значительной степени не важно, пока Вы знаете поведение, когда это переносится - и это указано в документации.

13
ответ дан 1 December 2019 в 06:59
поделиться

Если вы хотите проверить, что происходит при переносе GetTickCount () , вы можете включить проверку приложения. Тест TimeRollOver.

Из Использование верификатора приложения в жизненном цикле разработки программного обеспечения :

TimeRollOver заставляет API-интерфейсы GetTickCount и TimeGetTime выполнять пролонгацию быстрее, чем обычно. Это позволяет приложениям легче тестировать обработку смены времени.

7
ответ дан 1 December 2019 в 06:59
поделиться

Я недавно натыкался на ту проблему. Код, который я работал над используемым GetTickCount () в наборе мест, чтобы определить, проводила ли программа слишком много времени на конкретной задаче и раз так она была бы тайм-аут, что задача и переносит ее для более позднего выполнения. То, что произошло бы, - то, что, если бы GetTickCount () перенесся в течение одного из периодов измерения, он вызвал бы код к тайм-ауту преждевременно. Это было сервисом, который работает постоянно, поэтому каждые 49 дней, он имел бы легкое отклонение.

Я зафиксировал его путем записи класса таймера, который использовал GetTickCount () внутренне, но обнаружил когда значение, перенесенное и компенсированное его.

2
ответ дан 1 December 2019 в 06:59
поделиться

Вы можете протестировать его;) - У меня есть простое тестовое приложение, которое запустит приложение и подключит GetTickCount () в нем, чтобы вы могли управлять им из графического интерфейса тестового приложения. Я написал это как отключение вызовов GetTickCount () в некоторых приложениях не так просто.

TickShifter бесплатен и доступен здесь: http://www.lenholgate.com/ blog / 2006/04 / tickshifter-v02.html

Я написал его во время написания серии статей по разработке через тестирование, в которой использовался некоторый код, который использовал GetTickCount () неработающим способом.

Статьи доступны здесь, если вам интересно: http://www.lenholgate.com/blog/2004/05/practical-testing.html

Тем не менее, в итоге ваш код будет работать ...

1
ответ дан 1 December 2019 в 06:59
поделиться

Конечно, необходимо обработать эту галочку, переносят проблему.

Дескрипторы ядра Linux такая галочка переносят проблему со следующим приемом:

#define time_after (a, b) ((длинный) (b) - (длинный) (a) <0))

Идея брошена неподписанная к со знаком, и сравните их значение, затем только если |a-b | <2^30, затем перенос не влияет на результат.

Вы можете иметь попытку с этим приемом и добраться, изучают, почему он работает.

Так как DWORD является также неподписанным интервалом, этот прием должен также работы для окон.

Таким образом, Вы кодируете, мог быть sth как:

константа интервал DWORD = 20000;

DWORD отсчитывает = GetTickCount () + интервал;

в то время как (верный) {

DoTasksThatTakeVariableTime();

if(time_after(ticks, GetTickCount())
{
    DoIntervalTasks();
    ticks = GetTickCount() + interval;
} 

}

Только если интервал меньше, чем 0x2^30, это работает.

1
ответ дан 1 December 2019 в 06:59
поделиться

Я бы посоветовал рассчитать фактический прошедший период между двумя тактами, не полагаясь на компилятор, который сделает это за вас:

const DWORD interval = 20000;

#define TICKS_DIFF(prev, cur) ((cur) >= (prev)) ? ((cur)-(prev)) : ((0xFFFFFFFF-(prev))+1+(cur))

DWORD ticks = GetTickCount();
while(true)
{
    DoTasksThatTakeVariableTime();

    DWORD curticks = GetTickCount();
    if( TICKS_DIFF(ticks, curticks) > interval )
    {
        DoIntervalTasks();
        ticks = GetTickCount();
    }
}
4
ответ дан 1 December 2019 в 06:59
поделиться

Происходит Большой взрыв. Ой, извините, большой взрыв накрывает.

1
ответ дан 1 December 2019 в 06:59
поделиться

Эта статья мне помогла, но я думаю, что в ней есть ошибка:

#define TICKS_DIFF(prev, cur) ((cur) >= (prev)) ? ((cur)-(prev)) : ((0xFFFFFFFF-(prev))+(cur))

Когда я тестировал это в точке перехода, я обнаружил, что она отключена на 1.

Что сработало для меня было:

define TICKS_DIFF(prev, cur) ((cur) >= (prev)) ? ((cur)-(prev)) : ((0xFFFFFFFF-(prev))+(cur)+1)
1
ответ дан 1 December 2019 в 06:59
поделиться
Другие вопросы по тегам:

Похожие вопросы: