OpenMp:如何使尺寸std :: vector threadprivate

时间:2019-07-03 09:56:25

标签: c++ multithreading openmp

我是OpenMp领域的新手,但遇到一个错误,我无法修复。 原始代码很重要,所以我做了一个小代码来总结问题:

我得到了一个更高维度的std::vector(2d和3d),不应在线程之间共享。如果我将它们标记为私有,则它们仍会导致内存错误,因为线程仍共享它们。

我想出了一个解决该问题的方法: 我为2d向量创建了1维,因此每个线程都可以访问自己的副本:

myVector[omp_get_thread_num()][1].push_back(i);

我知道这不是解决我问题的明智方法,但是现在每个线程都有自己的2d Vector副本。 现在出现一个奇怪的部分:如果我不将#pragma omp critial放在它前面,有时仍然会导致内存崩溃。 我真的不明白为什么要这样做,因为线程永远都不能访问相同的内存。

#include <iostream>
#include <omp.h>
#include <vector>

//this should represent my problem(without my fix)
int main(){
        std::vector < std::vector < int > > v;
    v.resize(3);

    #pragma omp parallel for num_threads(2) private(v)
    for(int i = 0; i < 10; i++){
            v[1].push_back(i); 
    }
    return 0;
}

我希望有一个更好的解决方案,使我的2d向量线程私有。

ps。无法在omp部分内分配向量。

3 个答案:

答案 0 :(得分:1)

您必须了解,声明为private的来自外部作用域的变量的工作方式就像是在没有初始化程序的情况下在本地声明的 。因此每个本地副本都是一个空向量,因此您的代码无法正常工作。

通常,最好使用OpenMP在本地声明私有变量-这样可以避免根本没有连接的“外部值”和“内部私有值”之间的混淆。您可以通过拆分parallelfor指令来实现此目的。

#pragma omp parallel
{
    std::vector<std::vector<int>> v;
    v.resize(3);
    #pragma omp for
    for(int i = 0; i < 10; i++){
        v[1].push_back(i); 
    }
}

请注意,v在并行区域之后不可用-很好!在您的原始示例中,v在并行区域之后可用-但是它的值与内部线程的值无关。

如果您需要保留来自v的信息,则可能需要查看减少量,但这取决于您的特定用例。

您的myVector[omp_get_thread_num()]方法是一种普通的幼稚方法。该代码是正确的代码,但是在任何情况下修改最外面的向量的值 ,由于共享错误,它的性能不佳。 / p>

myVector[omp_get_thread_num()].push_back(); // Bad performance
myVector[omp_get_thread_num()][1].push_back(i); // Ok

因此,通常建议不要执行此操作,而应使用局部声明的变量。但是,如果您的此代码崩溃,则还有其他问题。在这种情况下,您需要准备minimal reproducible example,然后问第二个问题(引用此问题)。

现在threadprivateprivate不同。 private通常是您想要的,它指的是特定的任务/范围。在大多数情况下,您不需要threadprivate

答案 1 :(得分:0)

您可以使用thread_local存储说明符:

int main(){
   thread_local std::vector < std::vector < int > > v;
   // ...
}

答案 2 :(得分:0)

您没有指定有关原始代码的许多重要细节。但是,一种方法可能是先创建一个并行节,然后在其中定义私有向量,然后并行化循环。对于您的示例代码,它可能类似于:

int main() {
   #pramga omp parallel
   {
      std::vector<std::vector<int>> v;
      v.resize(3);

      #pragma omp for 
      for (int i = 0; i < 10; i++)
         v[1].push_back(i); 
   }
}