Ваш код не определяет настраиваемое сокращение для OpenMP, чтобы уменьшить собственные объекты. Я не уверен, поддерживает ли clang определяемое пользователем сокращение (см. OpenMP 4 spec, стр. 180). В таком случае вы можете объявить сокращение и добавить reduction(+:result)
в строку #pragma omp for
. Если нет, вы можете сделать это самостоятельно, изменив свой код следующим образом:
VectorXd result(500000); // This is the final result, not used by the threads
result.fill(0.);
double E = start;
result = integrand(E);
#pragma omp parallel
{
// This is a private copy per thread. This resolves race conditions between threads
VectorXd resultPrivate(500000);
resultPrivate.fill(0.);
#pragma omp for nowait// reduction(+:result) // Assuming user-defined reductions aren't allowed
for (int j = 1; j <= n; j++) {
E = start + (2 * j - 1.)*h;
resultPrivate = resultPrivate + 4.*integrand(E);
if (j != n) {
E = start + 2 * j*h;
resultPrivate = resultPrivate + 2.*integrand(E);
}
}
#pragma omp critical
{
// Here we sum the results of each thread one at a time
result += resultPrivate;
}
}
Ошибка, которую вы получаете (в вашем комментарии), похоже, связана с размером несоответствие. Хотя в самом вашем коде нет ничего тривиального, не забывайте, что когда OpenMP запускает каждый поток, он должен инициализировать частный VectorXd
для каждого потока. Если ничего не указано, по умолчанию будет VectorXd()
(с нулевым размером). Когда этот объект используется, возникает несоответствие размеров. «Правильное» использование omp declare reduction
будет включать часть инициализатора:
#pragma omp declare reduction (+: VectorXd: omp_out=omp_out+omp_in)\
initializer(omp_priv=VectorXd::Zero(omp_orig.size()))
omp_priv
- это имя частной переменной. Он инициализируется VectorXd::Zero(...)
. Размер указывается с помощью omp_orig
. Стандарт (стр. 182, строки 25-27) определяет это как:
Специальный идентификатор omp_orig также может появиться в предложении инициализатора, и он будет относиться к хранилищу исходной переменной, которая будет уменьшена.
В нашем случае (см. Полный пример ниже) это result
. Итак, result.size()
равно 500000, и приватная переменная инициализирована до правильного размера.
#include <iostream>
#include <string>
#include <Eigen/Core>
#include <omp.h>
using namespace Eigen;
using namespace std;
VectorXd integrand(double E)
{
VectorXd answer(500000);
double f = 5.*E + 32.*E*E*E*E;
for (int j = 0; j != 50; j++) answer[j] = j*f;
return answer;
}
#pragma omp declare reduction (+: Eigen::VectorXd: omp_out=omp_out+omp_in)\
initializer(omp_priv=VectorXd::Zero(omp_orig.size()))
int main()
{
omp_set_num_threads(4);
double start = 0.;
double end = 1.;
int n = 100;
double h = (end - start) / (2.*n);
VectorXd result(500000);
result.fill(0.);
double E = start;
result = integrand(E);
#pragma omp parallel for reduction(+:result)
for (int j = 1; j <= n; j++) {
E = start + (2 * j - 1.)*h;
result += (4.*integrand(E)).eval();
if (j != n) {
E = start + 2 * j*h;
result += (2.*integrand(E)).eval();
}
}
for (int i = 0; i < 50; ++i)
cout << i + 1 << " , " << result[i] << endl;
return 0;
}
person
Avi Ginsburg
schedule
14.11.2016
firstprivate(params) reduction(+:result_int)
в своюparallel
директиву, удалитеcritical
и повторите попытку ... - person Gilles   schedule 09.11.2016#pragma
читает#pragma omp parallel firstprivate(params) reduction(+:result_int)
, второй оператор#pragma
остается как есть, а все последующие#pragma
операторы удалены. Затем программа выдает ошибку времени выполнения:....const Eigen::Matrix<double, -1, 1, 0, -1, 1> >]: Assertion aLhs.rows() == aRhs.rows() && aLhs.cols() == aRhs.cols()' failed. Aborted
- Я могу гарантировать, что и kspace, и result_int имеют одинаковое количество элементов и размерность. - person AlexD   schedule 09.11.2016integrand(...)
, и ваш код не компилируется. Вы также не ответили, возвращает ли серийная версия правильный результат. - person Avi Ginsburg   schedule 14.11.2016