delay
в основном цикле на самом деле не очень хороший способ для этого (поскольку он не учитывает время, которое занимает другой материал в вашей основной петле). Когда вы удалили задержку, то скорость больше и варьируя больше, потому что другие вещи в вашей основной синхронизации контура является более значительными и, как правило, не постоянным, по многим причинам, как:
- OS зернистость
- синхронизации с GFX карты/водитель
- не постоянное время обработки
Есть несколько способов, как справиться с этим:
мера времени
<pre>
t1=get_actual_time();
while (t1-t0>=animation_T)
{
siguienteSprite++;
t0+=animation_T;
}
// t0=t1; // this is optional and change the timing properties a bit
</pre>
где t0
некоторая глобальная переменная холдинга "последний" измеряется время изменения ОС спрайтов. t1
- фактическое время и animation_T
- постоянная времени между изменениями анимации. Чтобы измерить время, вам нужно использовать OS api как PerformanceCounter
на окнах или RDTSC
в asm или любом другом, что вы получили под рукой, но с достаточно небольшим разрешением.
таймер OS
просто увеличиваем siguienteSprite
в некоторых таймер с animation_T
интервалом. Это просто, но таймеры ОС не являются точными и обычно составляют около 1 мс или более. Гранулярность ОС (аналогична точности Sleep
).
таймер Thread
вы можете создать один поток для целей синхронизации, например, что-то вроде этого:
for (;!threads_stop;)
{
Delay(animation_T); // or Sleep()
siguienteSprite++;
}
Не забывайте, что siguienteSprite
должен быть volatile
и буферизацией во время рендеринга, чтобы избежать мерцания и или ошибки нарушения доступа. Этот подход немного более точен (если только у вас нет единого ядра CPU).
Вы также увеличиваете переменную времени и используете это как фактическое время в своем приложении с любым требуемым разрешением.Но будьте осторожны, если delay
не возвращается CPU управления для OS, этот подход будет использовать ваш CPU в 100%/CPU_cores
. Существует средство для этого, и что меняет ваш delay
с этим:
Sleep(0.9*animation_T);
for (;;)
{
t1=get_actual_time();
if (t1-t0>=animation_T)
{
siguienteSprite++;
t0=t1;
break;
}
Если вы используете измеренное время, то вы должны обращаться с переполнением (t1<t0)
, потому что любой счетчик будет переполняться времени. Например, используя 32-разрядную часть RDTSC по адресу 3.2 GHz
Ядро центрального процессора будет переполняться каждые 2^32/3.2e9 = 1.342 sec
, поэтому это реальная возможность. Если моя память хорошо работает, то счетчики производительности в Windows обычно работают около 3.5 MHz
по более старым системам OS и около 60-120 MHz
на более новых (по крайней мере, в последний раз, когда я проверяю) и 64 бит, поэтому переполнение не так уж и много для проблемы (если только вы 24/7). Также в случае использования RDTSC вы должны установить привязку процесса/нити к одиночному CPU ядро, чтобы избежать проблем с синхронизацией на многоядерном процессоре CPU s.
Я сделал мою долю бенчмаркинга и расширенному времени с высоким разрешением на низком уровне в течение многих лет, так вот несколько связанных QA s шахты:
wrong clock cycle measurements with rdtsc - OS Зернистость
Measuring Cache Latencies - измерение частоты процессора
Cache size estimation on your system? - PerformanceCounter
пример
Questions on Measuring Time Using the CPU Clock - PIT как альтернативный источник синхронизации