首页 > 解决方案 > 声明减少向量,在 1 个线程上运行与没有 openmp 的结果不同

问题描述

即使我在 1 个线程上运行它,我的以下代码也会给出错误的答案。如果注释掉 for 循环之前的两个 pragma,则代码给出正确的结果。怎么会这样?我认为在 1 个线程上,使用 OpenMP 和不使用 OpenMP 没有区别,除了可能有一些小的开销。另外,我应该怎么做才能获得“正确的行为”?当我只有一个 for 循环时,我没有同样的问题,但是超过 1 个时,它不会像我想的那样工作。

#include<iostream>
#include<vector>
#include<algorithm>
#include<omp.h>
using namespace std;
#pragma omp declare reduction(vec_double_plus : std::vector<double> : \
                              std::transform(omp_out.begin(), omp_out.end(), omp_in.begin(), omp_out.begin(), std::plus<double>())) \
                    initializer(omp_priv = omp_orig)

int main() {
    vector<int> v;
    vector<double> w(2);
    for (int i = 0; i < 1000; i++) {
        if (i % 2 == 0) {
            v.push_back(0);
        }
        else {
            v.push_back(1);
        }
    }
    #pragma omp parallel for reduction(vec_double_plus:w)
    for (int i = 0; i < 500; i++) {
        int r = v[i];
        w[r] += i;
    }
    #pragma omp parallel for reduction(vec_double_plus:w)
    for (int i = 500; i < 1000; i++) {
        int r = v[i];
        w[r] += i;
    }
    std::cout << w[0] << std::endl;
    std::cout << w[1] << std::endl;
}

标签: c++openmp

解决方案


问题是,代码假定来自外部范围的原始变量是用归约的中性元素初始化的——即w全零。它将从此外部创建本地副本并将其再次添加到原始副本中。这甚至发生在单个线程上。

您可以更改代码以omp_priv使用零进行初始化,如下所示:

initializer(omp_priv = decltype(omp_orig)(omp_orig.size()))

代码对我来说很熟悉,很抱歉造成混淆。我会修复原来的答案。


推荐阅读