Ответ 1
Только в Fortran в OpenMP 3.0 и, вероятно, только с определенными компиляторами.
См. последний пример (Пример 3):
http://wikis.sun.com/display/openmp/Fortran+Allocatable+Arrays
Поддерживает ли 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-параллели есть что-то подобное, и если у вас есть достаточно большое количество потоков, чтобы это имело смысл, накопление произойдет через двоичное дерево.
Только в Fortran в OpenMP 3.0 и, вероятно, только с определенными компиляторами.
См. последний пример (Пример 3):
http://wikis.sun.com/display/openmp/Fortran+Allocatable+Arrays
Теперь с OpenMP 4.5 для 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 4.5 поддерживает сокращение массивов 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 не может выполнять сокращения по переменным типа массива или структуры (см. ограничения).
Вы также можете прочитать private
и shared
. private
объявляет переменную частной для каждого потока, где shared
объявляет переменную, которая будет использоваться для всех потоков. Я также нашел ответ на этот question очень полезный для OpenMP и массивов.
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
должен соответствовать вектору, который вы планируете уменьшить.