2015-04-23 2 views
0

Я не могу найти хороший ответ на это:C++ - Выполнить функцию каждые X миллисекунд

Я сделать игру, и я хочу, логика цикла быть отделена от графического цикла. Другими словами, я хочу, чтобы игра проходила через цикл каждые X миллисекунд независимо от количества кадров в секунду.

Очевидно, что оба они будут делиться множеством переменных, поэтому я не могу передавать поток/таймер одной переменной взад и вперед ... Я в основном ищут способ иметь таймер в фоновом режиме что каждые X миллисекунды отправляют флаг для выполнения логического цикла, независимо от того, где находится графический цикл.

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

+1

Лучший вариант - это * не * иметь два потока, если только вам это не нужно. Синхронизация потоков не для слабонервных, и требует значительных усилий, чтобы получить право (без этого быстро превращается в код блокировки-спагетти, во всяком случае). В своем основном цикле просто вызывайте функцию каждый раз, когда количество миллисекунд с момента последнего вызова превышает ваш порог (и затем сбрасывает счетчик). – Cameron

+0

_ «Очевидно, что обе они будут делиться множеством переменных», вы можете делиться данными между потоками. Просто используя [соответствующие механизмы блокировки] (http://en.cppreference.com/w/cpp/thread/mutex) для чтения/записи общих данных для предотвращения условий гонки. Вам не нужно переводить данные_. –

+0

Это действительно простая идея, но вы можете просто заключить цикл вокруг кода в своей основной функции и использовать оператор if для вычисления системных часов для * x * миллисекунд. – Slothrop

ответ

3

Вы можете очень хорошо выполнять многопоточность, если ваш «мир» обменял каждый тик. Так вот как это работает:

  1. Ваше текущее мировоззрение указывает один смарт-указатель и только для чтения, поэтому не замок не требуется.
  2. Ваша логика создает ваше (первое) мировоззрение, публикует его и планирует рендеринг.
  3. Ваш рендеринг захватывает копию указателя на ваш взгляд на мир и сохраняет его (помните, только для чтения)
  4. А пока ваша логика создает новое, немного другое мировоззрение.
  5. Когда это сделано, он обменивает указатель на текущий вид мира, публикуя его как текущий.
  6. Даже если средство визуализации по-прежнему занято старым взглядом на мир, блокировки не требуется.
  7. В конечном итоге рендеринг завершает рендеринг (старого) мира. Он захватывает новое мировоззрение и начинает еще один прогон.
  8. В то же время, ... (Гото шаг 4)

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

+0

'std :: shared_ptr' - ваш друг здесь –

0

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

+0

Итак, вы предлагаете решение использовать одиночный игровой цикл и вообще не многопоточность? –

+0

Да, он мог сделать это, используя массив компонентов в своем главном. затем используйте insanceof, чтобы увидеть, является ли его DrawableGameComponent или jsut gameComponenet. Кроме того, он может использовать игровое время для отключения части .draw(), если его время заканчивается. –

+1

Вы, вероятно, должны набросать это в своем ответе (давая небольшой пример кода для интерфейсов и т. Д.). –

0

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

Если вы работаете в системе unix, вы можете использовать usleep(), но это не доступно для окон, поэтому вы можете посмотреть here для альтернатив.

1

В большинстве наборов инструментов есть цикл событий (построенный над некоторым мультиплексированием, например, poll(2)) или устаревшим select -...), например.GTK имеет g_application_run (который выше :) gtk_main, который построен выше Glib main event loop (что на самом деле делает poll или что-то подобное). Аналогично, Qt имеет QApplication и его методы exec.

Очень часто вы можете регистрировать таймеры в цикле событий. Для GTK используйте GTimer s, g_timeout_add и т. Д. Для Qt узнайте о его timers.

Очень часто, вы можете также зарегистрировать некоторые простаивает или фон обработка, которая является одной из вашей функции, которая запускается цикл обработки событий после того, как другие события и интервалы времени были обработаны. Ожидается, что ваша незанятая функция будет работать быстро (обычно это небольшой шаг некоторых вычислений за несколько миллисекунд, чтобы поддерживать графический интерфейс в ответном режиме). Для GTK используйте g_idle_add и т. Д. IIRC, в Qt вы можете использовать таймер с задержкой 0.

Таким образом, вы можете кодировать даже (концептуально) однопоточное приложение, используя таймауты и обработку в режиме ожидания.

Конечно, вы можете использовать многопоточность: обычно основной поток запускает цикл событий, а другие потоки могут выполнять другие функции. У вас проблемы с синхронизацией. В POSIX-системах хорошей трюкой синхронизации может быть использование pipe(7) для себя: вы настраиваете канал перед запуском цикла событий, и ваши потоки вычислений могут записывать на нем несколько байтов, тогда как цикл основного события «прослушивает» он (с GTK, используя g_source_add_poll или async IO или GUnixInputStream и т. д., с Qt, используя QSocketNotifier и т. д.). Затем, во входном обработчике, запущенном в основном цикле для этого канала, вы можете получить доступ к традиционным глобальным данным с помощью мьютексов и т. Д.

Понятно, прочитайте о continuations. Это важное понятие.

 Смежные вопросы

  • Нет связанных вопросов^_^