OpenMP:task_reduction=减少?什么是 'in_reduction'?

OpenMP: task_reduction=reduction? What is 'in_reduction'?

是否'task_reduction'与'reduction ([ reduction-modifier ,] reduction 标识符:列表)'与任务缩减修饰符? 如果相同,那为什么我们需要'task_reduction'?

'in_reduction'在做什么? 文中说 'The in_reduction clause specifies that a task participates in a reduction ' 但是,这是什么意思?在 'in_reduction' 中,我们需要与 reduction 相同的子句。

in_reduction(identifier : list)

但是如果我们可以在 'list' 中放置缩减变量,那么这对 'task participates in reduction' 有什么作用...?

我可以想象减少是如何工作的,但我无法想象 'in_reduction'。 为什么我们需要它?

======================================

我举了个例子。此代码应在偶数索引号

处给出 num 的总和
#include <stdio.h>
#include <stdlib.h>
#include <omp.h>
int main(int argc, char* argv[]){

        int Array [10]= {0,1,2,3,4,5,6,7,8,9};
        int Array_length = 10;
        int counter = 0;
        int result = 0;

        #pragma omp parallel
        #pragma omp single 

        {
        #pragma omp taskgroup task_reduction(+:result)
        //#pragma omp parallel reduction(task,+:result) this can work same as taskgroup task_reduction?
        {
             while (Array_length!=counter){
                  if (counter%2==0){
                      #pragma omp task in_reduction(+:result)
                      {
                          result+=Array[counter];
                      }
                  }else {
                          result+=Array[counter];
                  }
                  counter=counter+1;
             }
        }
    }
    printf("The sum of all array elements is equal to %d.\n", result);
}

而且我还做了一个插图,所以我可以形象地理解我的理解。

所以……task_reduction创建一个reduction,这样就可以贡献本地结果,只有in_reduction的任务才会参与Reduction的贡献?

如果我没理解错的话,这段代码的结果应该是 20。但是,我的代码给出了 45,这是 0 到 9 的总和。

我哪里弄错了?

顺便说一句,如果我根本不写'in_reduction'会怎样?那么结果是0?

任务缩减的工作方式是任务需要知道将其本地结果贡献给哪里。所以,你要做的是有一个任务组来“创造”减少,然后让任务为它做出贡献:

void example() {
    int result = 0;
#pragma omp parallel   // create parallel team
#pragma omp single     // have only one task creator
    {
        #pragma omp taskgroup task_reduction(+:result)
        {
            while(have_to_create_tasks()) {
                #pragma omp task in_reduction(+:result)
                {   // this tasks contribute to the reduction
                    result = do_something();
                }
                #pragma omp task firstprivate(result)
                {   // this task does not contribute to the reduction
                    result = do_something_else();
                }
            }
        }
    }
}

因此,任务需要 in_reduction 才能促成由封闭 taskgroup 区域的 task_reduction 子句创建的减少。

reduction 子句不能与 task 结构一起使用,只能与工作共享结构和其他循环结构一起使用。

唯一具有 reduction 子句的任务构造是 taskloop 构造,它使用它作为隐藏 task_reduction 构造的快捷方式,该构造包含所有循环构造它创建然后也有一个隐藏的 in_reduction 子句。

更新(以覆盖原始发布者的编辑):

代码的问题是现在发生了两件事(请参阅更新代码中的内联注释):

#include <stdio.h>
#include <stdlib.h>
#include <omp.h>
int main(int argc, char* argv[]){
    int Array [10]= {0,1,2,3,4,5,6,7,8,9};
    int Array_length = 10;
    int counter = 0;
    int result = 0;

    #pragma omp parallel
    #pragma omp single
    {
        #pragma omp taskgroup task_reduction(+:result)
        {
            // "result" is a shared variable in this parallel region
            while (Array_length!=counter) {
                if (counter%2==0){
                    #pragma omp task in_reduction(+:result)
                    {
                        // This task will contribute to the reduction result
                        // as you would expect.
                        result+=Array[counter];
                    }
                } else {
                    // This addition to "result" is performed by the "single"
                    // thread and thus hits the shared variable.  You can see
                    // this when you print the address of "result" here
                    // and before the parallel region.
                    result+=Array[counter];
                }
                counter=counter+1;
            }
        } // Here the "single" thread waits for the taskgroup to complete
          // and the reduction to happen.  So, here the shared variable
          // "result" is added to the value of "result" coming from the
          // task reduction.  So, result = 25 from the "single" thread and
          // result = 20 are added up to result =45
    }
    printf("The sum of all array elements is equal to %d.\n", result);
}

任务减少结束时的添加似乎是竞争条件,因为来自 single 线程的更新和来自任务组末尾的更新不同步。我猜比赛没有出现,因为代码太快无法清楚地暴露它。

要修复代码,您还必须围绕奇数更新构建一个 task 结构,如下所示:

#include <stdio.h>
#include <stdlib.h>
#include <omp.h>
int main(int argc, char* argv[]){
    int Array [10]= {0,1,2,3,4,5,6,7,8,9};
    int Array_length = 10;
    int counter = 0;
    int result = 0;

    #pragma omp parallel
    #pragma omp single
    {
        #pragma omp taskgroup task_reduction(+:result)
        {
            // "result" is a shared variable in this parallel region
            while (Array_length!=counter) {
                if (counter%2==0){
                    #pragma omp task in_reduction(+:result)
                    {
                        // This task will contribute to the reduction result
                        // as you would expect.
                        result+=Array[counter];
                    }
                } else {
                    #pragma omp task firstprivate(result)
                    {
                        // "result" is now a task-local variable that is not
                        // shared.  If you remove the firstprivate, then the
                        // race condition on the shared variable "result" is
                        // back.
                        result+=Array[counter];
                    }
                }
                counter=counter+1;
            }
        } // Here the "single" thread waits for the taskgroup to complete
          // and the reduction to happen.  So, here the shared variable
          // "result" is added to the value of "result" coming from the
          // task reduction.  So, result = 25 from the "single" thread and
          // result = 20 are added up to result =45
    }
    printf("The sum of all array elements is equal to %d.\n", result);
}

在我的第一个回答中,我没有为任务添加适当的 firstprivateprivate 子句。我很抱歉。