Java: параллелизм для игры - PullRequest
1 голос
/ 26 декабря 2009

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

У меня есть метод main в классе Game. Каждый из потоков игрока работает над решением. В определенные моменты игрок будет «очищать». Во время этой операции каждому игроку предоставляется новая плитка. Один из потоков игрока должен уведомить поток Game.

Псевдокод будет выглядеть примерно так:

while (no player has reported they are finished) {
      if (player reports it is time to peel) {
           everyone peel 
      }
      everyone work towards completion of puzzle
}

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

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

Ответы [ 3 ]

4 голосов
/ 26 декабря 2009

Это было бы хорошим местом для использования циклического барьера .

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

Таким образом, вы можете очистить каждый игрок, а затем вызвать CyclicBarrier.await (). Затем все потоки будут ждать, пока каждый не достигнет этой точки. Что, кажется, то, что вы хотите.

(Кроме того, вам явно не нужен параллелизм для этого:)

1 голос
/ 26 декабря 2009

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

Один из способов решения этой проблемы - настроить очередь событий.

в псевдокоде

 enum EVENTTYPES = {PEEL=0, WORK=1};
 struct Event = {
     int eventType;
     int* data;
 }

 filoQueue eventQueue;

 array sQuidPlayers = [new Squid(), new Squid(), new Squid()];
 void eventLoop () {
      int player;
      for each player in sQuidPlayers {
          eventQueue.push(new Event(EVENTTYPES.WORK, player.id));
      }

      for each event in eventQueue {
           game.doEvent(event)
      }

 }

Таким образом, здесь вы запускаете цикл обработки событий 25 раз, 30 раз или 60 раз в секунду, независимо от частоты кадров, с которой вы хотите работать. Вы используете таймер для этого (я уверен, что где-то есть в Java)

Затем doEvent попытается найти подходящий метод на экземпляре соответствующего игрока. Метод работы в классе Squid выполнит небольшую работу, а затем остановится, ожидая следующего цикла. Каждый Squid в массиве получает свою очередь, чтобы выполнить свою крошечную работу. Метод работы, в свою очередь, МОЖЕТ поместить событие PEEL в очередь событий. В этот момент, в следующий раз вокруг цикла, может быть вызван некоторый соответствующий метод отслаивания. Возможно, в каком-то центральном игровом классе с идентификатором игрока, который инициировал событие пилинга. Вы помещаете логику того, как отправлять эти события в метод doEvent. doEvent, в свою очередь, может передавать объект каждому получателю событий, так что получатель может помещать свои собственные объекты событий в очередь для последующего запуска в цикле. (поочередно цикл «для каждого события» выполняется до тех пор, пока очередь событий не станет пустой, что включает в себя новые события, только что добавленные предыдущими вызовами doEvent, поэтому новое событие можно вызвать немедленно, вместо ожидания следующего кадра анимации)

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

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

1 голос
/ 26 декабря 2009

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

Редактировать: вот ссылка на статью, в которой более подробно рассматривается реализация многопоточного шаблона Observer в Java. http://www.javaworld.com/jw-03-1999/jw-03-toolbox.html

...