OpenMP:如何在每个线程中利用递归函数?

Posted

技术标签:

【中文标题】OpenMP:如何在每个线程中利用递归函数?【英文标题】:OpenMP: How to utilize recursive function in each thread? 【发布时间】:2016-03-24 22:20:09 【问题描述】:
#include <stdio.h>
#include<array>
#include<vector>
#include <omp.h>

std::vector<int> pNum;
std::array<int, 4> arr;
int pGen(int);
int main()

    pNum.push_back(2);
    pNum.push_back(3);
    pGen(10);
    for (int i = 0; i < pNum.size(); i++)
    
        printf("%d \n", pNum[i]);
    
    printf("top say: %d", pNum.size());
    getchar();

int pGen(int ChunkSize)

    //
    if (pNum.size() == 50) return 0;
    int i, k, n, id;
    int state = 0;

        //
#pragma omp parallel for schedule(dynamic) private(k, n, id) num_threads(4)
        for (i = 1; i < pNum.back() * pNum.back(); i++)
        
            //
            id = omp_get_thread_num();
            n = pNum.back() + i * 2;
            for (k = 1; k < pNum.size(); k++)
            
                //
                if (n % pNum[k] == 0) break;
                if (n / pNum[k] <= pNum[k])
                
                    //
#pragma omp critical
                    
                        //
                        if (state == 0)
                        
                            //
                            state = 1; pNum.push_back(n); printf("id: %d; number: %d \n", id, n); pGen(ChunkSize);  break;
                        
                    
                   
            
            if (state == 1) break;
        


这是我上面的代码。我正在尝试使用 openMP 调度为每个动态、静态和引导找到前 50 个素数。我从动态开始。不知何故,我意识到我必须使用递归函数,因为我不能使用 do - 在并行结构中。

当我调试上面的代码时,控制台立即打开和关闭,我只能看到“id:0, number:5”和一个“error: blablabla(something)”

奇怪的是我从来没有得到 getchar() 并输出我用来存储素数的向量。我认为这是关于递归函数。还有其他理论吗?

编辑:我碰巧发现了错误: this is the error

【问题讨论】:

@HighPerformanceMark,因为 OP 正在使用 Visual Studio(从链接的屏幕截图中可以看出),她/他被 OpenMP 2.0 卡住了,所以没有明确的任务。 是的,我正在使用 VS。有没有关于openMP的详细教程网页。我找不到任何深入而详细的例子。另外,我可以在VS中增加openMP的错误记录和抛出功能吗? 这越来越有趣了。我添加了 omp_set_nested(1);因为我使用嵌套循环,现在只有 thread_0 正确生成 50 个素数并抛出此错误:'Fatal User Error 1002:'#pragma omp barrier'不正确地嵌套在工作共享结构中'......我没有在任何地方使用屏障在代码中。我开始觉得 VS 惹我了。 如果您只寻找 50 个素数,那么 OpenMP 中隐含的线程创建等开销将永远无法恢复!所以你的序列号会更快... 【参考方案1】:

我不知道这对您的算法是否重要,但由于您在主循环期间在pNum 向量中添加数字,pNum.back() 将随着迭代而改变。因此,并行循环的边界将在循环本身期间发生变化:for (i = 1; i &lt; pNum.back() * pNum.back(); i++)

OpenMP 不支持此功能。只有在 Canonical Loop Form 中的循环才能与 OpenMP 并行化。该链接详细解释了它,但它归结为您应该在进入循环之前知道并修复边界:

lb 和 b:与 var 的类型兼容的类型的循环不变表达式

因此,您的代码具有未定义的行为。它可能会或可能不会编译,可能会或可能不会运行,并且可以给出任何结果(或者只是重新格式化您的硬盘)。

如果pNum.back() 在迭代中演化并不重要,那么您可以简单地在循环之前对其进行评估,并将此值用作for 语句中的上限。但如果它很重要,那么您将不得不找到另一种方法来并行化您的循环。

最后,附注:此算法使用嵌套并行,但您并没有明确允许这样做,因为嵌套并行默认禁用,只有最外层对 pGen() 的调用会生成 OpenMP 线程。

【讨论】:

以上是关于OpenMP:如何在每个线程中利用递归函数?的主要内容,如果未能解决你的问题,请参考以下文章

c中的openmp并行递归函数

使用openmp进行合并排序

java 中递归的实现 以及利用递归方法实现汉诺塔

如何在matlab中利用函数的递归调用求n!

第六章 函数和宏定义实验

递归:如何利用递归求解汉诺塔问题?