У меня есть двумерная сетка n
Иксn
элементы. В одной итерации я вычисляю значение одного элемента путем усреднения значений его соседей. То есть:
for(int i=0;i<n;i++)
for(int j=0;j<n;j++)
grid[i][j] = (grid[i-1][j] + grid[i][j-1] + grid[i+1][j] + grid[i][j+1])/4.0;
И мне нужно запустить вышеупомянутый вложенный цикл для iter
количество итераций.
Что мне нужно, это следующее:
iter
итерации будут выполняться последовательно, но в течение каждая итерация, значение grid[i][j]
для каждого i
а также j
следует рассчитывать параллельно.Для этого у меня есть следующие идеи и вопросы:
grid[i][j]
сделав только эти 4 элемента частный в тему. (В основном сетка используется всеми потоками, но есть локальная копия 4 итерация конкретных элементы в каждой теме тоже.) Это возможно?barrier
на самом деле нужно, чтобы все потоки закончили и затем начали следующую итерацию?Я очень новичок в мышлении OpenMP и совершенно потерян в этой простой проблеме. Я был бы признателен, если бы кто-то мог помочь разрешить мою путаницу.
На практике вы хотели бы иметь (намного) меньше потоков, чем точек сетки, поэтому каждый поток будет вычислять целый набор точек (например, одну строку). Существуют определенные накладные расходы, связанные с запуском потоков OpenMP (или любого другого вида), и ваша программа в любом случае будет связана с памятью, а не с процессором. Таким образом, запуск потока для каждой точки сетки уничтожит всю цель распараллеливания вычислений. Следовательно, ваша идея № 1 не рекомендуется (хотя я не совсем уверен, что правильно ее понял; возможно, это не то, что вы предлагали).
Я бы порекомендовал (также отмеченный другими в комментариях OP), что вы выделяете вдвое больше памяти, необходимой для хранения значений сетки, и используете два указателя, которые меняются местами между итерациями: один указывает на память, содержащую предыдущие значения итерации, которые доступны только для чтения, другой к новым значениям итерации, которые доступны только для записи. Обратите внимание, что вы будете менять местами только указатели, а не копировать память. После завершения итерации вы можете скопировать конечный результат в нужное место.
Да, вам нужно синхронизировать потоки между итерациями, однако в OpenMP это обычно делается неявно, просто открывая параллельную область внутри цикла итерации (в конце параллельной области есть неявный барьер):
for (int iter = 0; iter < niter; ++iter)
{
#pragma omp parallel
{
// get range of points for current thread
// loop over thread's points and apply the stencil
}
}
или, используя parallel for
построить:
const int np = n*n;
for (int iter = 0; iter < niter; ++iter)
{
#pragma omp parallel for
for (int ip = 0; ip < np; ++ip)
{
const int i = ip / n;
const int j = ip % n;
// apply the stencil to [i,j]
}
}
Вторая версия автоматически распределяет работу между доступными потоками, что, скорее всего, то, что вы хотите. Во первых вы должны сделать это вручную.
Других решений пока нет …