Пятница, 29 Ноября 2024, 03:07

Приветствую Вас Гость

[ Новые сообщения · Игроделы · Правила · Поиск ]
  • Страница 1 из 1
  • 1
проблема с распараллеливанием
puksusДата: Воскресенье, 12 Ноября 2017, 12:09 | Сообщение # 1
Пчёлка Зоя
Сейчас нет на сайте
Хочу разделить игру на 4 потока (пока что) . Пока что это чисто тестовые потоки, которые ничего не делают, хочу хоть как-то заставить их работать.

Идея такова:
1)инициализирую эти потоки перед вхождением в главный игровой цикл.
2)эти потоки внутри крутят бесконечный цикл, но вначале каждой итерации ждут оповещения от главного потока, чтобы он разрешил им работать
3)внутри главного игрового цикла каждую итерацию я оповещаю эти потоки о том, что они могут выполнить очередную итерацию по формированию кадра.
4)Тогда эти потоки снимаются с паузы и выполняют итерацию, после чего они должны оповестить главный поток о том, что они завершили работу и снова находятся на паузе.
5)главный поток ждёт оповещения ото всех запущенных потоков
6)следующая итерация главного игрового цикла.

Проблема: где-то получаю дедлок на рандомной итерации главного игрового цикла и в упор не понимаю, почему. Это мой первый опыт с многопоточкой, буду рад, если скажете, что у меня в коде не так и почему, потому что я ещё не совсем влился в тему.

Код делает дедлок даже если запустить 1 поток вместо 4-х, поэтому я 3 других даже закомментил, чтобы не мешались.

Главной функцией потока является ф-ция action()
Она принимает аргументом ту функцию, которую должен вызывать поток собственно для работы.
Внутри она крутит бесконечный цикл и ждёт разрешения на работу.
Когда разрешение получено, она выполняет нужную функцию (например, render()), которая, в свою очередь, по завершении, даёт главному потоку информацию о том, что работа завершилась

Ф-ция update() вызывается из главного цикла и оповещает потоки о том, что они могут начинать работу, после чего ждёт завершения их выполнения.

В общем, нужен хелп, долбусь уже целый день.



Добавлено (11 ноября 2017, 17:49)
---------------------------------------------
Кажись, решил проблему небольшим костылём
Как было устроено: все потоки в начале фрейма ждут разрешение на работу, главный поток им его даёт. Потом он ждёт когда потоки оповестят его о завершении работы. При этом, для того чтобы обновить инфу о прогрессе работы потоков, использовался тот же мьютекс, который использовался в условной переменной, которая ждала результат. Возможно, потому я и ловил дедлок
как решил: убрал условную переменную, которая ждала пока потоки не завершат кадр и не лочу в главном потоке соответствующий мьютекс.
Вместо этого заставляю главный поток в цикле проверять, закончена ли работа и ждать. Так что, теперь итерация главного цикла (ф-ция update) выглядит так


Сами потоки в конце работы вызывают ф-цию


Результат: 10к пустых итераций главного цикла проходят за 11-12 секунд => 900 кадров в секунду, не так уж и плохо.



Добавлено (11 ноября 2017, 18:02)
---------------------------------------------
попробую теперь на этапе инициализации проверять, сколько ядер в компе юзера.
Если 4+ - запускать 3-4 потока
Если 2 - запускать 2 потока, в первом - рендер+что-то не слишком тяжёлое, во втором - всё остальное
Если 1 - 2 потока, рендер в одном, всё остальное во втором

Добавлено (11 ноября 2017, 22:15)
---------------------------------------------
Всё, обернул всё это дело в класс. Можно создать произвольное количество потоков, в каждый из потоков запихнуть произвольное количество последовательно исполняемых задач.

Только одна проблема есть: сделал синглтон, отнаследовался от него и попытался получать инстанс нужного класса, не получалось - психанул и удалил наследование от синглтона, всё равно я один над проектом сижу, и так знаю, что класс в единственном экземпляре должен быть))





Добавлено (12 ноября 2017, 12:09)
---------------------------------------------
упс, ещё один дедлок был, который случался довольно редко (тобишь прога стабильно работала несколько десятков секунд в полной нагрузке, прежде чем валилась)
На этот раз связанный со "spurious wakeup"

Дело в том, что может так совпасть, что поток сорвётся по ложному прерыванию за павру мгновений до того, как главный поток оповестит его о начале работы. Таким макаром, когда главный поток его оповещает, тот всё ещё занят обработкой ложного прерывания и усыплением себя, а ведь оповещение из главного потока прошло мимо! А потом мы ждём завершения работы потока, в то время как он пропустил оповещение о начале работы.
Вылечил так: в цикле спамим оповещения, разблокируя при этом мьютекс условной переменной до тех пор, пока не убедимся, что наше сообщение дошло



https://vk.com/beezoya

Сообщение отредактировал puksus - Суббота, 11 Ноября 2017, 19:45
  • Страница 1 из 1
  • 1
Поиск:

Все права сохранены. GcUp.ru © 2008-2024 Рейтинг