Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/126.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 如何解决多线程代码中for循环中的依赖关系?_C++_Multithreading_Parallel Processing_Openmp - Fatal编程技术网

C++ 如何解决多线程代码中for循环中的依赖关系?

C++ 如何解决多线程代码中for循环中的依赖关系?,c++,multithreading,parallel-processing,openmp,C++,Multithreading,Parallel Processing,Openmp,我无法使用OpenMP解决for循环中的依赖项,因此程序将执行得更快。这就是我如何做到的,它的工作原理,但我需要一个更快的解决方案。有人知道怎么做才能更快地工作吗 #pragma omp parallel for num_threads(tc) ordered schedule(dynamic, 1) private(i) shared(openSet, maxVal, current, fScores) for(i = 0;i < openSet.size

我无法使用OpenMP解决for循环中的依赖项,因此程序将执行得更快。这就是我如何做到的,它的工作原理,但我需要一个更快的解决方案。有人知道怎么做才能更快地工作吗

        #pragma omp parallel for num_threads(tc) ordered schedule(dynamic, 1) private(i) shared(openSet, maxVal, current, fScores)
        for(i = 0;i < openSet.size();i++){
            if(fScores[openSet[i].x * dim + openSet[i].y] < maxVal){
                #pragma omp ordered
                maxVal = fScores[openSet[i].x * dim + openSet[i].y];
                current = openSet[i];
            }
        }

首先,你需要确定,这是你的热点。然后给我们一个合适的测试套件,以确保您实际获得性能。使用“google_benchmark”等工具。确保您是在发布模式下编译的,否则您的度量将被完全破坏

这就是说,我认为你正在寻找最大的减少

 #pragma omp parallel for reduction(max : maxVal )
    for(i = 0;i < openSet.size();i++){
        if(fScores[openSet[i].x * dim + openSet[i].y] > maxVal){

            maxVal = fScores[openSet[i].x * dim + openSet[i].y];

        }
    }
#pragma omp并行减少(max:maxVal)
对于(i=0;imaxVal){
maxVal=fScores[openSet[i].x*dim+openSet[i].y];
}
}
“当前”接缝是多余的。我认为这种比较混淆了

您能否以线性方式访问“fScores”中的数据。使用“openSet”上的间接寻址将有大量缓存未命中。如果您能够以某种方式摆脱这种间接方式,那么在单线程和多线程的情况下,您将获得很高的加速比

在第二个循环中,“推回”会破坏你的表现。我也有类似的问题。对我来说,这是非常有益的

  • 创建具有最大可能长度的向量
  • 用空值初始化它
  • 使用符合标准的openmp正确设置
  • 使用向量时,检查空值

首先,您需要确保这是您的热点。然后给我们一个合适的测试套件,以确保您实际获得性能。使用“google_benchmark”等工具。确保您是在发布模式下编译的,否则您的度量将被完全破坏

这就是说,我认为你正在寻找最大的减少

 #pragma omp parallel for reduction(max : maxVal )
    for(i = 0;i < openSet.size();i++){
        if(fScores[openSet[i].x * dim + openSet[i].y] > maxVal){

            maxVal = fScores[openSet[i].x * dim + openSet[i].y];

        }
    }
#pragma omp并行减少(max:maxVal)
对于(i=0;imaxVal){
maxVal=fScores[openSet[i].x*dim+openSet[i].y];
}
}
“当前”接缝是多余的。我认为这种比较混淆了

您能否以线性方式访问“fScores”中的数据。使用“openSet”上的间接寻址将有大量缓存未命中。如果您能够以某种方式摆脱这种间接方式,那么在单线程和多线程的情况下,您将获得很高的加速比

在第二个循环中,“推回”会破坏你的表现。我也有类似的问题。对我来说,这是非常有益的

  • 创建具有最大可能长度的向量
  • 用空值初始化它
  • 使用符合标准的openmp正确设置
  • 使用向量时,检查空值

    • 在我看来,您似乎误解了OpenMP ordered子句的实际作用。从中可以看出:

      有序构造可以指定 工作共享循环、simd或工作共享循环simd区域将 按照循环迭代的顺序执行,或者它是独立的 指令,指定doacross中的交叉迭代依赖项 环巢。有序构造对 执行有序区域,同时允许区域外的代码 并行运行

      :

      ordered子句的工作原理如下:执行不同的线程 同时,直到它们遇到有序区域,然后 按顺序执行,其顺序与在 串行循环

      根据您使用它的方式,似乎您将ORDER子句误认为是OpenMP子句:

      关键构造限制了关联操作的执行 一次将结构化块转换为单个线程

      所以,使用ordered子句,您的代码基本上是按顺序运行的,并带有额外的并行开销。然而,即使您使用了关键构造函数,开销也会太高,因为线程会在每次循环迭代中锁定

      对于第一个循环,乍一看,您可以使用OpenMP
      reduce
      子句(即
      reduce(max:maxVal)
      ),它可以从标准中读取:

      reduce子句可用于执行某些形式的重复 并行计算(…)。用于并行计算和工作共享 构造时,将创建每个列表项的私有副本,每个列表项对应一个副本 隐式任务,就好像使用了private子句一样。(……)该 然后按照上面的指定初始化私有副本。最后 为其指定缩减子句的区域,原始列表 项目通过将其原始值与最终值相结合进行更新 使用指定的 还原标识符

      关于减损条款如何工作的更详细的解释,请看下面的例子

      尽管如此,您仍在更新两个变量,即
      maxVal
      current
      。因此,仅使用reduce子句就很难解决这些依赖关系。尽管如此,一种方法是在线程之间创建共享数据结构,其中每个线程更新该共享结构的给定位置。在并行区域的末尾,主线程相应地更新
      maxVal
      current
      的原始值

      因此,不是:

       #pragma omp parallel for num_threads(tc) ordered schedule(dynamic, 1) private(i) shared(openSet, maxVal, current, fScores)
          for(i = 0;i < openSet.size();i++){
              if(fScores[openSet[i].x * dim + openSet[i].y] < maxVal){ // <-- you meant '>' not '<'
                  #pragma omp ordered
                  maxVal = fScores[openSet[i].x * dim + openSet[i].y];
                  current = openSet[i];
              }
          }
      

      在我看来,您误解了OpenMP ORDER子句的实际功能。从中可以看出:

      有序构造可以指定 工作共享循环、simd或工作共享循环simd区域将 按照循环迭代的顺序执行,或者它是独立的 指定交叉迭代de的指令
       #pragma omp parallel for num_threads(tc) ordered schedule(dynamic, 1) private(i) shared(openSet, maxVal, current, fScores)
          for(i = 0;i < openSet.size();i++){
              if(fScores[openSet[i].x * dim + openSet[i].y] < maxVal){ // <-- you meant '>' not '<'
                  #pragma omp ordered
                  maxVal = fScores[openSet[i].x * dim + openSet[i].y];
                  current = openSet[i];
              }
          }
      
          int shared_maxVal[tc] = {INT32_MAX};
          int shared_current[tc] = {0};
          #pragma omp parallel num_threads(tc)
          { 
              int threadID = omp_get_thread_num();
              #pragma omp for shared(openSet, fScores)
              for(int i = 0;i < openSet.size();i++){ 
                 if(fScores[openSet[i].x * dim + openSet[i].y] > shared_maxVal[threadID]){
                    shared_maxVal[threadID] = fScores[openSet[i].x * dim + openSet[i].y];
                    shared_current[threadID] = openSet[i];
                 }
              }
          }
       
          for(int i = 0; i < tc; i++){
             if(maxVal < shared_maxVal[i]){
                maxVal = shared_maxVal[i];
                current = shared_current[i];
             }
          } 
      
      #pragma omp parallel for num_threads(tc) ordered schedule(dynamic, 1) private(i) shared(neighbours, openSet, gScores, fScores, tentative_gScore)
      for(i = 0;i < neighbours.size();i++){
          #pragma omp ordered
          tentative_gScore = gScores[current.x * dim + current.y] + 1;
      
          if(tentative_gScore < gScores[neighbours[i].x * dim + neighbours[i].y]){
              cameFrom[neighbours[i].x * dim + neighbours[i].y] = current;
              gScores[neighbours[i].x * dim + neighbours[i].y] = tentative_gScore;
              fScores[neighbours[i].x * dim + neighbours[i].y] = tentative_gScore + hScore(); //(p.x, p.y, xEnd, yEnd)
              if(contains(openSet, neighbours[i]) == false){
                  openSet.push_back(neighbours[i]);
              }
          }
      }
      
          // Create an array of "openSets" let us named "shared_openSet"
          #pragma omp parallel num_threads(tc)
          {  
             int threadID = omp_get_thread_num();
             #pragma omp for shared(neighbours, gScores, fScores)
             for(int i = 0;i < neighbours.size();i++){
              // I just assume the type in but you can change if for the real type
              int tentative_gScore = gScores[current.x * dim + current.y] + 1;
      
              if(tentative_gScore < gScores[neighbours[i].x * dim + neighbours[i].y]){
                  cameFrom[neighbours[i].x * dim + neighbours[i].y] = current;
                  gScores[neighbours[i].x * dim + neighbours[i].y] = tentative_gScore;
                  fScores[neighbours[i].x * dim + neighbours[i].y] = tentative_gScore + hScore();
                  if(contains(openSet, neighbours[i]) == false){
                      shared_openSet[threadID].push_back(neighbours[i]);
                  }
              }
            }
         }
        // merge all the elements from shared_openSet into openSet.