2012-06-28 4 views
6

С OpenMP 3.1, можно иметь пункт reduction с min:найти минимальный элемент в массиве и его индекс

double m; 
#pragma omp parallel for reduction(min:m) 
for (int i=0;i< n; i++){ 
    if (a[i]*2 < m) { 
    m = a[i] * 2; 
} 
return m; 

Предположим, я также необходимо индекс минимального элемента; есть ли способ использовать для этого предложение reduction? Я считаю, что альтернатива записывает сокращение вручную, используя nowait и critical.

ответ

5

Предположим, мне также нужен индекс минимального элемента; есть ли способ использовать предложение сокращения для этого?

К сожалению, нет. список возможных сокращений в OpenMP очень ... маленький. В частности, min и max являются единственными функциями «более высокого уровня», и они не настраиваются. Вообще.

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

Для таких операций вам необходимо реализовать сокращение самостоятельно, скопировав локальные результаты потока в локальные переменные потока и объединив их в конце.

Самый простой способ сделать это (и, действительно, совсем близко к тому, как OpenMP реализует сокращения) - иметь массив с элементами для каждого потока и использовать omp_get_thread_num() для доступа к элементу. Обратите внимание, однако, что это приведет к снижению производительности из-за ложного обмена, если элементы массива разделяют линию кэша. Чтобы уменьшить это значение, введите массив:

struct min_element_t { 
    double min_val; 
    size_t min_index; 
}; 

size_t const CACHE_LINE_SIZE = 1024; // for example. 
std::vector<min_element_t> mins(threadnum * CACHE_LINE_SIZE); 

#pragma omp parallel for 
for (int i = 0; i < n; ++i) { 
    size_t const index = omp_get_thread_num() * CACHE_LINE_SIZE; 
    // operate on mins[index] … 
} 
+0

Я думаю, вы имели в виду 'omp_get_num_threads'? – user1071136

+0

@ user1071136 Нет, я имею в виду 'omp_get_thread_num'. Мы хотим * index *, а не общее число. А что касается 'threadnum', это местозаполнитель. Вы не можете использовать 'omp_get_num_threads' здесь, так как вы не находитесь в параллельном регионе. Вместо этого вы должны фактически передать 'numthread' как число потоков в следующем параллельном предложении. –

+0

+1 для обозначения ложного обмена. Тем не менее, предложения OpenMP для сокращения были разработаны для повышения эффективности и простоты реализации, а не для экстенсибили. –

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