2013-12-01 3 views
0

Я написал довольно сложную программу, которая имитирует поведение мелких клеток-подобных организмов в системе частиц.Многопоточность моделирования в C++

Моделирование проходит через несколько этапов, где вычисляется следующая позиция для каждого объекта в моделировании. Функция-член движения «движение» вызывается для каждой частицы и организма в симуляции, которая обновляет его векторы перемещения (в случае организма он обрабатывает AI и движение). Затем функция рендеринга выполняет итерацию по каждому объекту и рисует соответствующую форму при новом перемещении каждого объекта.

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

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

Как я уже упоминал ранее, новые позиции каждого объекта вычисляются путем итерации по каждому объекту и вызова функции-члена текущего объекта, которая вычисляет новое положение для этого конкретного объекта. Мне было интересно, можно ли сделать этот процесс параллельно - вычислить одну четверть объектов в одном потоке, еще одну четверть во втором потоке и т. Д. Возможно ли это, и улучшит ли скорость вычислений для каждого кадра, когда огромное количество объектов в симуляции?

+2

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

ответ

1

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

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

typedef World Cell[9][9]; // World is a 9x9 matrix of Cells 
World buffers[2]; // 2 buffers. 
World* src = buffers[0]; 
World* dst = buffers[1]; 

PopulateWorld(src); 

while (running) { 
    PerformTransformations((const World*)src, (/*!const*/ World*)dst); 
    std::swap(src, dst); 
} 

В качестве альтернативы, вы можете маршал/инкапсулировать трансформируемое свойство каждой ячейки в их собственные структуры/классы, так что каждая клетка имеет пару, и вы просто переключаться между ними.

struct Cell { 
    struct Data { 
     Matrix3d position; 
     Matrix3d velocity; 
    }; 

    Data m_data[2]; 

    static void DetermineWhichBuffersToUse(size_t runNo, size_t& srcNo, size_t& dstNo) { 
     // when runNo is even, use m_data[0] as src, 
     // when runNo is odd, use m_data[1] as src. 
     size_t src = (runNo & 1); 
     size_t dst = 1 - src 

    } 

    ... 
}; 

Другим вариант было бы использовать попутный трубопровод сообщения, в котором вы мобилизовывать все ячейки в запросы на обработку данных, имеете compuations сделанного рабочих потоков, которые выдают сообщение с результирующим набором данными обратно в родительской нить ,

Родительский поток отправляет все сообщения, а затем возвращает все результаты и записывает их. Это решение более целесообразно для исследования, если вы планируете масштабировать моделирование по нескольким системам, и в этом случае вам может понадобиться посмотреть что-то вроде ZeroMQ для библиотеки передачи сообщений.

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