Я отвечу на ваш вопрос в трех частях:
1. Как лучше всего выполнить сокращения OpenMP в приведенном выше примере с std::vec
?
i) Используйте ваш подход, то есть создайте указатель int* val { &vec[0] };
ii) Объявите новую совместно используемую переменную, такую как @ 1201ProgramAlarm answer.
iii) объявите определяемое пользователем сокращение (что в действительности не применимо в вашем простом случае, но см. ниже 3. для более эффективный шаблон).
2. Почему не работает третий l oop и почему он работает с Eigen?
Как и в предыдущем ответе, вы говорите OpenMP выполнить сокращение суммы для адреса памяти X , но вы выполняете дополнения по адресу памяти Y, что означает, что объявление сокращения игнорируется, и ваше добавление подвергается обычным условиям состязания потоков.
Вы не очень подробно рассказываете о своем предприятии Eigen, но вот некоторые возможные объяснения:
i) Вы на самом деле не используете несколько потоков (отметьте n = Eigen::nbThreads( )
)
ii) Вы не отключили собственный параллелизм Эйгена, который может нарушить ваш собственный использование OpenMP, например EIGEN_DONT_PARALLELIZE
директива компилятора.
iii) Условие гонки есть, но вы его не видите, потому что операции Eigen занимают больше времени, вы используете небольшое количество потоков и только пишете небольшое количество значений => меньшее количество потоков, мешающих друг другу, чтобы дать неправильный результат.
3. Как мне распараллелить этот сценарий, используя OpenMP (технически это не вопрос, который вы задали явно)?
Вместо распараллеливания только внутреннего l oop, вы должны распараллелить оба в одно и то же время. Чем меньше серийный код у вас есть, тем лучше. В этом сценарии у каждого потока есть своя собственная копия вектора vec
, которая уменьшается после суммирования всех элементов их соответствующим потоком. Это решение является оптимальным для вашего представленного примера, но может столкнуться с проблемами ОЗУ, если вы используете очень большой вектор и очень много потоков (или у вас очень ограниченное ОЗУ).
#pragma omp parallel for collapse(2) reduction(vsum : vec)
for (unsigned int i {0}; i<vec.size(); ++i){
for (int j = 0; j < n; ++j) {
vec[i] += j;
}
}
, где vsum - пользователь определенное сокращение, т.е.
#pragma omp declare reduction(vsum : std::vector<int> : std::transform(omp_out.begin(), omp_out.end(), omp_in.begin(), omp_out.begin(), std::plus<int>())) initializer(omp_priv = decltype(omp_orig)(omp_orig.size()))
Объявите сокращение перед функцией, в которой вы его используете, и у вас все будет хорошо до go