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

Почему Sleep (500) стоит более 500 мс?

Я использовал Sleep(500) в своем коде, и я использовал getTickCount() для проверки времени. Я обнаружил, что он имеет стоимость около 515 мс, более 500. Кто-нибудь знает, почему это?

4b9b3361

Ответ 1

Поскольку Win32 API Sleep не является высокоточным сном и имеет максимальную детализацию.

Лучший способ получить прецизионный сон - спать немного меньше (~ 50 мс) и делать ожидание. Чтобы найти точное количество времени, которое требуется для занятости, получите разрешение системных часов с помощью timeGetDevCaps и умножьте на 1,5 или 2, чтобы быть в безопасности.

Ответ 2

sleep(500) гарантирует сон не менее 500 мс.

Но он может спать дольше: верхний предел не определен.

В вашем случае также будут дополнительные накладные расходы при вызове getTickCount().

Ваша нестандартная функция Sleep может вести себя по-другому; но я сомневаюсь, что точность гарантирована. Для этого вам нужно специальное оборудование.

Ответ 3

Как вы можете прочитать документацию, функцию WinAPI GetTickCount()

ограничивается разрешением системного таймера, который обычно находится в диапазоне от 10 миллисекунд до 16 миллисекунд.

Чтобы получить более точное измерение времени, используйте функцию GetSystemDatePreciseAsFileTime

Кроме того, вы не можете полагаться на Sleep(500), чтобы спать ровно 500 миллисекунд. Он будет приостанавливать поток не менее 500 миллисекунд. Затем операционная система продолжит поток, как только у него будет доступный временной интервал. Когда в операционной системе запущено много других задач, может возникнуть задержка.

Ответ 4

В общем спящем означает, что ваш поток переходит в состояние ожидания, и после 500 мс он будет находиться в состоянии "runnable". Затем планировщик ОС решает запустить что-то в соответствии с приоритетом и количеством запущенных процессов в это время. Так что если у вас есть высокоточный сон и часы с высокой точностью, то он по-прежнему остается сна как минимум 500 мс, а не ровно 500 мс.

Ответ 5

Как и другие ответы, Sleep() имеет ограниченную точность. На самом деле, реализация Sleep() -подобной функции может быть абсолютно точной по нескольким причинам:

  • Для фактического вызова Sleep() требуется некоторое время. Хотя реализация, нацеленная на максимальную точность, может попытаться измерить и компенсировать эти накладные расходы, мало беспокоит. (И, в любом случае, накладные расходы могут варьироваться в зависимости от многих причин, включая использование ЦП и памяти.)

  • Даже если таймер, используемый в Sleep(), срабатывает точно в нужное время, нет гарантии, что ваш процесс будет фактически перенесен сразу после пробуждения. Возможно, ваш процесс был заменен, когда он спал, или другие процессы могут запугать CPU.

  • Возможно, что ОС не может разбудить ваш процесс в указанное время, например. потому что компьютер находится в режиме ожидания. В таком случае вполне возможно, что ваш вызов 500 мс Sleep() на самом деле в конечном итоге займет несколько часов или дней.

Кроме того, даже если Sleep() был совершенно точным, код, который вы хотите запустить после сна, неизбежно потребует дополнительного времени. Таким образом, для выполнения некоторых действий (например, перерисовки экрана или обновления игровой логики) через регулярные интервалы, стандартное решение должно использовать компенсированный цикл Sleep(). То есть вы поддерживаете регулярно увеличивающийся счетчик времени, указывающий, когда должно произойти следующее действие, и сравните это целевое время с текущим системным временем, чтобы динамически отрегулировать время сна.

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

Вот краткий пример реализации (в псевдокоде), который должен обрабатывать обе эти проблемы:

int interval = 500, giveUpThreshold = 10*interval;
int nextTarget = GetTickCount();

bool active = doAction();
while (active) {
    nextTarget += interval;
    int delta = nextTarget - GetTickCount();
    if (delta > giveUpThreshold || delta < -giveUpThreshold) {
        // either we're hopelessly behind schedule, or something
        // weird happened; either way, give up and reset the target
        nextTarget = GetTickCount();
    } else if (delta > 0) {
        Sleep(delta);
    }
    active = doAction();
}

Это гарантирует, что doAction() будет вызываться в среднем один раз каждые interval миллисекунды, по крайней мере, до тех пор, пока он не будет последовательно потреблять больше времени, чем до тех пор, пока не произойдет больших переходов времени. Точное время между последовательными вызовами может отличаться, но любое такое изменение будет компенсировано при следующем посещении.

Ответ 6

Разрешение по умолчанию таймера низкое, при необходимости вы можете увеличить временное разрешение. MSDN

#define TARGET_RESOLUTION 1         // 1-millisecond target resolution

TIMECAPS tc;
UINT     wTimerRes;

if (timeGetDevCaps(&tc, sizeof(TIMECAPS)) != TIMERR_NOERROR) 
{
    // Error; application can't continue.
}

wTimerRes = min(max(tc.wPeriodMin, TARGET_RESOLUTION), tc.wPeriodMax);
timeBeginPeriod(wTimerRes); 

Ответ 7

Есть две общие причины, по которым код может нуждаться в функции типа "sleep":

  • У этого есть некоторая задача, которая может быть выполнена в любое время, по крайней мере, на некотором расстоянии в будущем.

  • У него есть некоторая задача, которая должна выполняться как можно ближе к некоторому моменту времени на некоторое расстояние в будущем.

В хорошей системе должны быть отдельные способы выдачи таких запросов; Windows делает первое проще, чем второе.

Предположим, что в системе есть один процессор и три потока, все из которых полезны работайте до одной секунды до полуночи, один из нитей говорит, что не будет что-нибудь полезное, чтобы сделать хотя бы секунду. В этот момент система будет посвятить выполнение оставшимся двум потокам. Если за 1 мс до полуночи, один из этих потоков решает, что для этого не будет ничего полезного во-вторых, система переключит управление на последний оставшийся поток.

Когда полночь катится, исходный первый поток станет доступным для но поскольку текущий исполняемый поток будет иметь только CPU для миллисекунда в этот момент, нет особой причины первоначальной первой поток должен считаться более "достойным" процессорного времени, чем другой поток который только что получил контроль. Поскольку потоки переключения не являются бесплатными, ОС может хорошо решить, что поток, который в настоящее время имеет процессор, должен поддерживать его до тех пор, пока он блокирует что-то или использует весь фрагмент времени.

Было бы неплохо, если бы была версия "сна", которая была проще в использовании чем мультимедийные таймеры, но потребует, чтобы система передавала поток ускорение временного приоритета, когда оно становится пригодным для повторного запуска или еще лучше вариация "сна", которая указывала бы минимальное время и "приоритет- ускоряйте "время, для задач, которые необходимо выполнить в течение определенного временного окна. Я не знаю никаких систем, которые могут быть легко созданы для работы таким образом.