Я просто дам другой подход.Мне нужен был аналогичный тиковый цикл, работающий со скоростью около 25 кадров в секунду.У меня есть класс с именем ApplicationLoop
, который при построении запускает поток.Этот поток - мой цикл приложения.(Отсюда и очевидное имя класса.)
Итак, у меня есть несколько констант для определения частоты кадров и запасного значения пропуска кадров.По сути, когда задача занимает больше времени, чем 40 мс (1000/25 = 40), я снова повторяю все задачи, чтобы «наверстать упущенное».Но я делаю это только несколько раз.
private const int MAX_FRAMESKIP = 5;
private const int UPDATE_SKIP_TICKS = 1000 / UPDATE_TICKS_PER_SECOND;
private const int UPDATE_TICKS_PER_SECOND = 25;
Моя функция потока:
private void UpdateLoop()
{
ulong ticks = 0UL;
_isRunning = true;
var next = DateTime.Now.Ticks / TimeSpan.TicksPerMillisecond;
while (_isRunning)
{
var now = DateTime.Now.Ticks / TimeSpan.TicksPerMillisecond;
int loops = 0;
while ((now > next) && _isRunning && (loops < MAX_FRAMESKIP))
{
ProcessTasks(ticks);
next += UPDATE_SKIP_TICKS;
loops++;
ticks++;
}
AccurateSleep(1);
}
}
Мой класс содержит функцию Subscribe()
, которая принимает делегата.Я сохраняю этот обратный вызов в List
, и функция ProcessTasks()
вызывает каждую подписанную функцию.
Вы можете заменить функцию AccurateSleep()
простым вызовом Thread.Sleep(1)
, но помните, что время по умолчаниюсрез для сна составляет около 15 мс.
[DllImport("winmm.dll")]
private static extern uint timeBeginPeriod(uint period);
[DllImport("winmm.dll")]
private static extern uint timeEndPeriod(uint period);
private static void AccurateSleep(int sleep)
{
timeBeginPeriod(1);
Thread.Sleep(sleep);
timeEndPeriod(1);
}