C++ OpenACC sum reduction输出在每次执行时递增sum

C++ OpenACC sum reduction输出在每次执行时递增sum,c++,cuda,gpgpu,openacc,pgi,C++,Cuda,Gpgpu,Openacc,Pgi,为什么会出现以下代码: #include <iostream> int main(int argc, char const *argv[]) { int sum = 0; int *array; array = new int [100]; #pragma acc enter data create(array[0:100],sum) #pragma acc parallel loop present(array[0:100])

为什么会出现以下代码:

#include <iostream>

int main(int argc, char const *argv[])
{
    int sum = 0;
    int *array;
    array = new int [100];

    #pragma acc enter data create(array[0:100],sum)

    #pragma acc parallel loop present(array[0:100])
    for (int i = 0; i < 100; ++i)
    {
        array[i] = 1;
    }

    #pragma acc parallel loop present(array[0:100],sum) reduction(+:sum)
    for (int i = 0; i < 100; ++i)
    {
        sum += array[i];
    }

    #pragma acc exit data delete(array[0:100]) copyout(sum)

    std::cout << sum << std::endl;

    return 0;
}
根据OpenACC标准:

在exit data指令上,数据被复制回本地内存并 解除分配

似乎
sum
不是解除分配,而是在程序每次运行时重复使用(并递增)。此外,
reduce
指令中的
+
运算符将reduce变量初始化为
0
,因此即使在执行之间未解除分配
sum
,也不会发生这种情况

我可以使用
enter data
指令中的
copyin
而不是
create
for
sum
,或者在单组单工作内核中设置
sum=0
来避免这种行为:

#pragma acc parallel present(sum) num_gangs(1) num_workers(1)
sum = 0;

但这并不令人满意,因为它需要昂贵的主机到设备数据拷贝(分别是内核启动)。为什么我的程序会这样运行?

您误解了还原运算符初始化值的含义。参考第20-21页:

在并行构造上允许使用reduction子句。它指定一个归约运算符和一个或多个标量变量。对于每个变量,为每个并行组创建一个私有副本,并为该运算符初始化。在区域的末尾,将显示 每个组使用归约运算符组合,结果与原始变量的值组合,并存储在原始变量中

这意味着整个减量问题被分解成几个部分,每个部分由一个帮派来处理。小组处理的问题部分将使用还原变量的指示初始化值。但是,当创建最终结果时,来自每个组的单个结果将与原始变量的值相结合(在您的情况下,
sum
),这就是结果

因此,您必须正确初始化
sum
,也许可以使用您在问题中概述的方法之一


另外,尽管这不是问题的关键,但请注意niether释放或分配对内存内容没有任何影响。在没有正确初始化的情况下,在该位置分配的新变量将在该位置获取当前值。

感谢您的清除。我猜设备内存中的
sum
的位置在执行过程中始终是相同的,并且揭示了OpenACC标准的(PGI)编译器实现的一些信息,这不是巧合吗?我不知道它揭示了什么。我可以用普通的CUDA代码做同样的事情(让一个未初始化的设备变量从一个运行到另一个运行被分配到相同的位置)。如果您多次运行完全相同的代码,您不希望它以相同的方式运行吗?这可能包括分配的位置。我不熟悉分配内存的标准编译器/操作系统行为,并假设给定变量不总是分配在内存中的同一位置。这是前缀扫描吗?
#pragma acc parallel present(sum) num_gangs(1) num_workers(1)
sum = 0;