В настоящее время я реализую многопоточный воксельный игровой движок. Когда я перехожу к многопоточности, я быстро сталкиваюсь с узким местом производительности из-за мьютексов.
Чтобы прояснить мою проблему, возьмем 2D-случай:
+-+-+-+
|A|B|C|
+-+-+-+
|D|E|F|
+-+-+-+
|G|H|I|
+-+-+-+
Все эти ячейки представляют собой воксельные блоки (16x16 вокселей).
Я использую все воксельные алгоритмы по частям, используя несколько потоков. У меня есть очередь заданий, состоящая из фрагментов, над которыми нужно работать, и каждый рабочий поток просто постоянно выбирает фрагменты из очереди и работает над ними.
Теперь представьте, что одному потоку нужно выполнить некоторые вычисления освещения в блоке E. Поскольку в углу E может быть источник света, который будет распространяться на соседние блоки, он должен заблокировать все девять соседних блоков, чтобы избежать потенциальной гонки данных, используя мьютексы. .
Однако, как я экспериментировал, накладные расходы на производительность с мьютексами невысоки. В настоящее время я использую простой цикл for
для добавления заданий. Итак, когда игра запускается, начальная очередь заданий будет выглядеть примерно так:
A, B, C, D, E, F, G, H, I, ...
Это действительно плохо, поскольку первое задание A блокирует A, B, D, E и выполняет все следующие восемь заданий в ожидании мьютексов, что снижает производительность.
В настоящее время я могу придумать единственное средство смягчения последствий - это попытаться добавлять рабочие места рассредоточенно, надеясь, что мы сможем избежать большинства задержек. Но мне не нравится этот подход, поскольку он больше похож на обходной путь и не очень гибкий при изменении схемы блокировки.
Я также подумал об использовании «асинхронных мьютексов». Но я не совсем уверен, как это сделать.
РЕДАКТИРОВАТЬ: Чтобы уточнить, задания освещения добавляются во время выполнения, а не в фиксированном порядке. Например, представьте, что игрок выходит из обрабатываемых в данный момент фрагментов, тогда в очередь должны быть добавлены только внешние фрагменты, которые могут находиться на нерегулярной границе.
Поэтому я считаю, что для решения этой проблемы недостаточно использовать только достойный планировщик.
B
во времяA
, просто переместитеB
в конец очереди и выберите следующий элемент. Конечно, это может не сработать, если вы уже поработали дляB
. Думаю, вы не хотите откатывать работу. - person Vincent van der Weele   schedule 23.04.2014E
, блокировкаA
,B
,C
, ...,I
, один за другим). Потому что мы не можем атомарно заблокировать все девять мьютексов одновременно, и эта схема может избежать тупиковых блокировок. Если он без мьютексов или, возможно, с использованием mutex.tryLock (), как избежать взаимоблокировок (и, возможно, живых блокировок)? - person Xiangyan Sun   schedule 23.04.2014