Запуск потока для каждого внутреннего цикла в OpenMP - PullRequest
6 голосов
/ 07 февраля 2010

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

По сути, это:

for (i = 0; i < dimension; i++) {
    for (int j = 0; j < dimension; j++) {
        a[i][j] = b[i][j] + c[i][j];

Что я делаю, это:

#pragma omp parallel for shared(a,b,c) private(i,j) reduction(+:diff) schedule(dynamic)
    for (i = 0; i < dimension; i++) {
        for (int j = 0; j < dimension; j++) {
            a[i][j] = b[i][j] + c[i][j];

На самом деле это запускает поток для каждого 2D-элемента или нет? Как бы я это проверить? Если это неправильно, как правильно это сделать? Спасибо!

Примечание: код был значительно упрощен

Ответы [ 2 ]

7 голосов
/ 07 февраля 2010

Только внешний цикл параллелен в вашем примере кода.Вы можете проверить, напечатав omp_get_thread_num() во внутреннем цикле, и вы увидите, что для данного i номер потока одинаков (конечно, этот тест является демонстративным, а не окончательным, поскольку разные прогоны будут давать разные результаты),Например, с:

#include <stdio.h>
#include <omp.h>
#define dimension 4

int main() {
    #pragma omp parallel for
    for (int i = 0; i < dimension; i++)
        for (int j = 0; j < dimension; j++)
            printf("i=%d, j=%d, thread = %d\n", i, j, omp_get_thread_num());
    }

я получаю:

i=1, j=0, thread = 1
i=3, j=0, thread = 3
i=2, j=0, thread = 2
i=0, j=0, thread = 0
i=1, j=1, thread = 1
i=3, j=1, thread = 3
i=2, j=1, thread = 2
i=0, j=1, thread = 0
i=1, j=2, thread = 1
i=3, j=2, thread = 3
i=2, j=2, thread = 2
i=0, j=2, thread = 0
i=1, j=3, thread = 1
i=3, j=3, thread = 3
i=2, j=3, thread = 2
i=0, j=3, thread = 0

Что касается остальной части вашего кода, вы можете добавить больше деталей в новый вопрос (трудно сказатьиз небольшого образца), но, например, вы не можете поставить private(j), когда j объявлен только позже.Это автоматически приватно в моем примере выше.Я думаю, diff - это переменная, которую мы не видим в примере.Кроме того, переменная цикла i автоматически является закрытой (из спецификации версии 2.5 - то же самое в спецификации 3.0)

Переменная итерации цикла в цикле forfor или параллельные для конструкции являются частными в этой конструкции.

Редактировать: все вышеперечисленное верно для кода, который вы и я показали, но вас может заинтересовать следующее.Для OpenMP версии 3.0 (доступно, например, в gcc версии 4.4 , но не в версии 4.3) есть предложение collapse, в котором вы можете написать код, как у вас, но с #pragma omp parallel for collapse (2) для распараллеливания обоих циклов(см. спецификацию ).

Редактировать : ОК, я скачал gcc 4.5.0 и запустил приведенный выше код, но используя collapse (2), чтобы получить следующий вывод, показывающий, что внутренний цикл теперь распараллелен:

i=0, j=0, thread = 0
i=0, j=2, thread = 1
i=1, j=0, thread = 2
i=2, j=0, thread = 4
i=0, j=1, thread = 0
i=1, j=2, thread = 3
i=3, j=0, thread = 6
i=2, j=2, thread = 5
i=3, j=2, thread = 7
i=0, j=3, thread = 1
i=1, j=1, thread = 2
i=2, j=1, thread = 4
i=1, j=3, thread = 3
i=3, j=1, thread = 6
i=2, j=3, thread = 5
i=3, j=3, thread = 7

Комментарии здесь (поиск «обходных путей») также актуальны для обходных путей в версии 2.5, если вы хотите распараллелить оба цикла,но приведенная выше спецификация версии 2.5 является довольно явной (см. несоответствующие примеры в разделе A.35 ).

0 голосов
/ 07 февраля 2010

Вы можете попробовать использовать вложенные параллельные форы omp (после вызова omp_set_nested(1)), но они не поддерживаются во всех реализациях openmp.

Итак, я предполагаю создать некоторую двумерную сетку и начать все потоки на сетке с одного (например, для фиксированной сетки нитей 4x4):

#pragma omp parallel for
for(k = 0; k < 16; k++)
{
    int i,j,i_min,j_min,i_max,j_max;
    i_min=(k/4) * (dimension/4);
    i_max=(k/4 + 1) * (dimension/4);
    j_min=(k%4) * (dimension/4);
    j_max=(k%4 + 1) * (dimension/4);

    for(i=i_min;i<i_max;i++)
      for(j=j_min;j<j_max;j++)
       f(i,j);

}
...