Можно ли создать локальную для потока копию выбранных элементов из общего 2D-массива в параллельной области? (Общий, закрытый, барьерный: OPenMP)

У меня есть двумерная сетка 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 количество итераций.
Что мне нужно, это следующее:

  1. Мне нужно, чтобы потоки вычислили это среднее значение, подождите, пока все потоки не закончат вычислять, и ТОГДА обновите сетку за один раз.
  2. Цикл с iter итерации будут выполняться последовательно, но в течение каждая итерация, значение grid[i][j] для каждого i а также j следует рассчитывать параллельно.

Для этого у меня есть следующие идеи и вопросы:

  1. Может быть, сделать сетку общий и поместите копию выбранных 4 элементов сетки, которая необходима для расчета grid[i][j] сделав только эти 4 элемента частный в тему. (В основном сетка используется всеми потоками, но есть локальная копия 4 итерация конкретных элементы в каждой теме тоже.) Это возможно?
  2. Был бы barrier на самом деле нужно, чтобы все потоки закончили и затем начали следующую итерацию?

Я очень новичок в мышлении OpenMP и совершенно потерян в этой простой проблеме. Я был бы признателен, если бы кто-то мог помочь разрешить мою путаницу.

0

Решение

  1. На практике вы хотели бы иметь (намного) меньше потоков, чем точек сетки, поэтому каждый поток будет вычислять целый набор точек (например, одну строку). Существуют определенные накладные расходы, связанные с запуском потоков OpenMP (или любого другого вида), и ваша программа в любом случае будет связана с памятью, а не с процессором. Таким образом, запуск потока для каждой точки сетки уничтожит всю цель распараллеливания вычислений. Следовательно, ваша идея № 1 не рекомендуется (хотя я не совсем уверен, что правильно ее понял; возможно, это не то, что вы предлагали).

  2. Я бы порекомендовал (также отмеченный другими в комментариях OP), что вы выделяете вдвое больше памяти, необходимой для хранения значений сетки, и используете два указателя, которые меняются местами между итерациями: один указывает на память, содержащую предыдущие значения итерации, которые доступны только для чтения, другой к новым значениям итерации, которые доступны только для записи. Обратите внимание, что вы будете менять местами только указатели, а не копировать память. После завершения итерации вы можете скопировать конечный результат в нужное место.

  3. Да, вам нужно синхронизировать потоки между итерациями, однако в 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]
    }
    }
    

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

2

Другие решения

Других решений пока нет …

По вопросам рекламы [email protected]