Можно ли сделать сокращение на массиве с помощью openmp?

Поддерживает ли OpenMP уменьшение переменной, представляющей массив?

Это будет работать что-то вроде следующего ...

float* a = (float*) calloc(4*sizeof(float));
omp_set_num_threads(13);
#pragma omp parallel reduction(+:a)
for(i=0;i<4;i++){
   a[i] += 1;  // Thread-local copy of a incremented by something interesting
}
// a now contains [13 13 13 13]

В идеале, было бы что-то подобное для параллельной omp, и если у вас достаточно большое количество потоков, чтобы это имело смысл, накопление происходило бы через двоичное дерево.

 Anycorn23 сент. 2010 г., 05:41
только в фортране
 Andrew Wagner27 сент. 2010 г., 21:52
Покопавшись еще немного, звучит как "только в фортране" - вот ответ. В итоге я просто выделил один большой массив локальных копий вне цикла, позволяя потокам накапливаться в свои собственные копии в цикле for, затем накапливаясь в глобальном массиве после цикла for, все еще находящемся внутри параллельной области внутри критический раздел.
 Andrew Wagner24 окт. 2010 г., 19:21
В итоге я вручную выделил место для локальных потоков копий массивов. Каждый поток выполняет 1/8 накопления в своей локальной копии, а затем потоки накапливают свою локальную копию в глобальной копии внутри критического блока #pragma omp. Поскольку число ядер (8) намного меньше n, накладные расходы на синхронизацию незначительны. Это не красиво, но это работает.
 Andrew Wagner01 окт. 2010 г., 16:05
Еще копая, вот исследовательская статья о чем-то похожем, но она еще не в openmp.springerlink.com/content/tq76655852630525
 Walter13 мая 2016 г., 23:30
использование OpenMP с C ++ не может быть рекомендовано: OpenMP не поддерживает последние стандарты C ++. С C ++ вы можете захотеть использоватьstd::threadS и т. д., илиТВВ
 Jonathan Dursi22 окт. 2010 г., 14:00
Вы можете, вероятно, использовать атомарный, а не критический, чтобы защитить отдельные добавления (или даже массив блокировок), если вы хотите уменьшить накладные расходы; Вы могли бы даже использовать массив совместно используемых массивов, а не частных массивов, и попытаться свернуть свое собственное двоичное сокращение. Но это будет некрасиво.
 FFox27 сент. 2010 г., 07:49
Может быть, вы могли бы объяснить немного больше, что именно вы хотите сделать. Предоставление серийного кода может помочь.

Ответы на вопрос(5)

Теперь последняя спецификация openMP 4.5 поддерживает сокращение массивов C / C ++.http://openmp.org/wp/2015/11/openmp-45-specs-released/

И последняя версия GCC 6.1 также поддерживает эту функцию.http://openmp.org/wp/2016/05/gcc-61-released-supports-openmp-45/

Но я еще не попробовал. Жаль, что другие могут проверить эту функцию.

Сокращение массива теперь возможно с OpenMP 4.5 для C и C ++. Вот пример:

#include <iostream>

int main()
{

  int myArray[6] = {};

  #pragma omp parallel for reduction(+:myArray[:6])
  for (int i=0; i<50; ++i)
  {
    double a = 2.0; // Or something non-trivial justifying the parallelism...
    for (int n = 0; n<6; ++n)
    {
      myArray[n] += a;
    }
  }
  // Print the array elements to see them summed   
  for (int n = 0; n<6; ++n)
  {
    std::cout << myArray[n] << " " << std::endl;
  } 
}

Выходы:

100
100
100
100
100
100

Я скомпилировал это с GCC 6.2. Вы можете увидеть, какие распространенные версии компилятора поддерживают функции OpenMP 4.5 здесь:http://www.openmp.org/resources/openmp-compilers/

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

OpenMP может выполнять эту операцию, поскольку OpenMP 4.5 и GCC 6.3 (и, возможно, ниже) поддерживают ее. Пример программы выглядит следующим образом:

#include <vector>
#include <iostream>

int main(){
  std::vector<int> vec;

  #pragma omp declare reduction (merge : std::vector<int> : omp_out.insert(omp_out.end(), omp_in.begin(), omp_in.end()))

  #pragma omp parallel for default(none) schedule(static) reduction(merge: vec)
  for(int i=0;i<100;i++)
    vec.push_back(i);

  for(const auto x: vec)
    std::cout<<x<<"\n";

  return 0;
}

Обратите внимание, чтоomp_out а такжеomp_in являются специальными переменными и что типdeclare reduction должен соответствовать вектору, который вы планируете уменьшить.

Решение Вопроса

Только в Фортране в OpenMP 3.0 и, вероятно, только с определенными компиляторами.

Смотрите последний пример (Пример 3) на:

http://wikis.sun.com/display/openmp/Fortran+Allocatable+Arrays

 Hugo Raguet02 июн. 2016 г., 16:55
Теперь это возможно начиная с OpenMP 4.5; см. ответ Чэнь Цзяна ниже. В основном, вы должны указатьразделы массива (см. раздел 2.4, стр. 44 спецификации OpenMP 4.5). Ваша спецификация #pragma будет выглядеть так:#pragma omp parallel reduction(+:a[:4])  Однако будьте осторожны с этим, вы должны понимать, что каждый поток будет выделять свою версию раздела массива; если вы делаете это на больших массивах с множеством потоков, вы можете заставить свою память взрываться.

OpenMP не может выполнять сокращения переменных массива или типа структуры (см.ограничения).

Вы также можете прочитать оprivate а такжеshared статьи.private объявляет переменную частной для каждого потока, где какshared объявляет переменную, которая будет совместно использоваться всеми потоками. Я также нашел ответ на этовопрос очень полезно в отношении OpenMP и массивов.

Ваш ответ на вопрос