2013-11-02 6 views
1

См редактировать ниже моего предварительного решенияPrivate «для» петли для каждого потока в OpenMP

Рассмотрим следующий код:

#include <stdio.h> 
#include <stdlib.h> 
#include <omp.h> 

int main(void) { 

int counter = 0; 
int i; 

omp_set_num_threads(8); 

#pragma omp parallel 
     { 
      int id = omp_get_thread_num(); 
      #pragma omp for private(i) 
      for (i = 0; i<10; i++) { 
       printf("id: %d thread: %d\n", i, id); 
       #pragma omp critical // or atomic 
       counter++; 
      } 
     } 

printf("counter %d\n", counter); 

return 0; 
} 

Я определяю количество нитей, чтобы быть 8. Для каждого из 8 потоков я хотел бы иметь цикл for для каждого отдельного потока, который увеличивает значение переменной counter. Тем не менее, кажется, что OpenMP распараллеливания for цикл:

i: 0 thread: 0 
i: 1 thread: 0 
i: 4 thread: 2 
i: 6 thread: 4 
i: 2 thread: 1 
i: 3 thread: 1 
i: 7 thread: 5 
i: 8 thread: 6 
i: 5 thread: 3 
i: 9 thread: 7 
counter 10 

Следовательно, counter=10, но я хочу counter=80. Что я могу сделать так, чтобы каждый поток выполнял свой собственный цикл for, пока все потоки увеличивались counter?

Следующий код дает желаемый результат: я добавил еще один внешний for петлю, что петли от 0 до максимального числа потоков. Внутри этого цикла я могу объявить мой цикл for частным для каждого потока. Действительно, counter=80 в этом случае. Является ли это оптимальным решением для этой проблемы или есть лучший?

int main(void) { 


omp_set_num_threads(8); 

int mthreads = omp_get_max_threads(); 

#pragma omp parallel for private(i) 
    for (n=0; n<mthreads; n++) { 
      int id = omp_get_thread_num(); 
     for (i = 0; i<10; i++) { 
      printf("i: %d thread: %d\n", i, id); 
      #pragma omp critical 
      counter++; 
     } 
    } 

} 
printf("counter %d\n", counter); 

return 0; 
} 

ответ

3

Решение очень простое - удалить распараллеливание построить for:

#pragma omp parallel 
    { 
     int id = omp_get_thread_num(); 
     for (int i = 0; i<10; i++) { 
      printf("id: %d thread: %d\n", i, id); 
      #pragma omp critical // or atomic 
      counter++; 
     } 
    } 

Декларирование i внутри контрольной части for является частью C99 и может потребовать, чтобы вы передать компилятору параметр, аналогичный -std=c99. В противном случае вы можете просто объявить i в начале блока. Или вы могли бы объявить его за пределами региона и сделать его private:

int i; 

#pragma omp parallel private(i) 
    { 
     int id = omp_get_thread_num(); 
     for (i = 0; i<10; i++) { 
      printf("id: %d thread: %d\n", i, id); 
      #pragma omp critical // or atomic 
      counter++; 
     } 
    } 

Поскольку вы не используете значение counter внутри параллельной области, вы можете также использовать сокращение суммы вместо:

#pragma omp parallel reduction(+:counter) 
    { 
     int id = omp_get_thread_num(); 
     for (int i = 0; i<10; i++) { 
      printf("id: %d thread: %d\n", i, id); 
      counter++; 
     } 
    } 
2

OpenMP имеет концепцию для этого, reduction. Остаться с вашим примером

#pragma omp parallel for reduction(+:counter) 
    for (unsigned n=0; n<mthreads; n++) { 
    int id = omp_get_thread_num(); 
    for (unsigned i = 0; i<10; i++) { 
     printf("i: %d thread: %d\n", i, id); 
     counter++; 
    } 
    } 

Это имеет то преимущество, чтобы не определять критический участок вокруг приращения. OpenMp собирает общее количество всех различных воплощений counter сам по себе и, вероятно, более эффективно.

Это даже может быть сформулирована гораздо проще, так как

#pragma omp parallel for reduction(+:counter) 
    for (unsigned i=0; i<mthreads*10; i++) { 
    int id = omp_get_thread_num(); 
    printf("i: %d thread: %d\n", i, id); 
    counter++; 
    } 

Для некоторых компиляторов вы, вероятно, все еще должны настаивать на том, с флагом, таких как -std=c99, что вы хотите, чтобы объявить переменные в цикле for. Преимущество при объявлении переменных как можно более локальным, вам не нужно настаивать на том, что они будут частными или что-то вроде этого. И самый простой способ - это, разумеется, иметь OpenMp разделить for -loop самостоятельно.

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