OpenMP任务 - 为什么会出现大量迭代~10k的分段错误?

时间:2017-10-24 20:39:25

标签: c parallel-processing segmentation-fault openmp

我使用以下代码来查找使用OpenMP任务构造的数组元素的总和 代码正在产生正确的结果,直到 n = 10000

但除此之外,我遇到了分段错误。使用 gdb ,我发现在reduce()的一次递归调用中发生了错误。输入数组分配没有问题,我已经验证了这一点。

有没有人对问题可能有什么建议?

int reduce (int *arr, unsigned long int n)
{   
    int x;
    if (n <= 0)
        return 0;

    #pragma omp parallel
    {   
        #pragma omp single nowait
        {   
            #pragma omp task shared(x)
            x = reduce(arr, n-1) + arr[n-1];
            #pragma omp taskwait
        }
    }
    return x;
}

2 个答案:

答案 0 :(得分:2)

看起来你正在通过函数调用的递归深度遇到“堆栈溢出”。请记住,大多数openmp pragma本身都会生成函数,这些函数可能会干扰尾递归优化。

如果你通过valgrind运行,它应该警告你堆栈溢出。

答案 1 :(得分:1)

dlasalle对于实际错误是正确的。

但是,关于如何使用OpenMP任务还有两个基本问题。您在每个递归调用中生成一个并行区域。这意味着您使用嵌套的并行区域。默认情况下,在OpenMP中禁用嵌套并行性,这里没有意义。您希望在递归期间生成的所有任务都由同一个线程池执行。为此,您必须将parallel / single移到递归之外,例如

int reduce_par(int* arr, unsigned long int n)
{
    int x;
    if (n <= 0)
        return 0;
    #pragma omp task shared(x)
    x = reduce_par(arr, n - 1) + arr[n - 1];
    #pragma omp taskwait
    return x;
}

int reduce(int* arr, unsigned long int n)
{
    #pragma omp parallel
    {
        #pragma omp single nowait
        {
            reduce_par(arr, n);
        }
    }
}

即使这不会出现段错误,即使你拥有无限数量的内核,具有无限的内存带宽和无线程创建开销,这仍然无法从并行化中获得任何性能优势。要弄清楚这一点,请绘制任务及其操作的图形并添加依赖项。尝试在时间轴上安排图表的节点,尊重任务依赖性,并查看是否可以并行计算任何内容。

并行求和的正确解决方案是具有parallel for子句的reduce工作共享构造。如果你不得不使用任务,你需要使用分而治之,例如为数组的两半产生两个任务。为了获得合理的性能,您必须以最小的工作负载大小停止创建任务/递归,以便保持开销的可管理性。