运行方法并等待完成所有 for 循环 openmp

Posted

技术标签:

【中文标题】运行方法并等待完成所有 for 循环 openmp【英文标题】:Run method and wait to finish all for loops openmp 【发布时间】:2013-05-23 20:09:15 【问题描述】:

我创建了 C++ 方法来查找数字的除数。第二步是在 C++ 中使用 openmp。 不幸的是,我无法管理为什么我的函数 doStuff 会抛出 memory error。可能问题出在线程上,我在所有线程停止之前检查了数组。有人可以帮我吗?

没有必要阅读我所有的程序,问题在doStuff()

#include <iostream>
#include <vector>
#include <string>
#include <cmath>
#include <algorithm>
#include "omp.h"

using namespace std;

vector<int> dividors;
int NUMBER = 1000;

bool ifContains(vector<int> element, int dividedNumber)

    for(int i=0; i<dividors.size(); i++)
    
        if(dividors[i] == dividedNumber)
            return true;
    

    return false;


void doStuff()

    int sqr = (int) sqrt(NUMBER);
    int sqrp1 = sqr + 1;

    #pragma omp parallel
    
    #pragma omp for nowait
        for (int i = 1; i < sqrp1; i++)
        
            if (NUMBER % i == 0)
            
                if (!ifContains(dividors, i))
                    dividors.push_back(i);

                int dividednumber = NUMBER / i;

                if (!ifContains(dividors,dividednumber))
                    dividors.push_back(dividednumber);
            
        


        sort(dividors.begin(), dividors.end());

        #pragma omp for nowait
        for (int i = 0; i < dividors.size(); i++)
        
            cout << dividors[i] << "\r\n";
        

    


int main()

    doStuff();
    return 0;


我也试过了,还是不行

void doStuff()

    int sqr = (int) sqrt(NUMBER);
    int sqrp1 = sqr + 1;

    #pragma omp parallel
    
        #pragma omp for
        for (int i = 1; i < sqrp1; i++)
        

            if (NUMBER % i == 0)
            
                if (!ifContains(dividors, i))
                    dividors.push_back(i);

                int dividednumber = NUMBER / i;

                if (!ifContains(dividors,dividednumber))
                    dividors.push_back(dividednumber);
            
        



        #pragma omp single
        sort(dividors.begin(), dividors.end());

        #pragma omp single
        for (int i = 0; i < dividors.size(); i++)
        
            cout << dividors[i] << "\r\n";
        

    

【问题讨论】:

element 是做什么的? 它是数组列表存储分隔符 是的,您将除数传递给 ifContains 方法,它以元素结束,但您不使用元素。 【参考方案1】:

有几种方法可以解决此问题。最简单的就是使用ordered 子句。请参阅下面的代码。但是,这消除了一些并行性。更好的方法是在并行块中声明私有除数向量(我称之为dividors_private),以便每个线程获得它自己的私有版本,然后写入关键块中的dividors 向量。排序是在私有向量上并行完成的。最后的排序是在单个线程中对dividors 完成的,但由于大部分已经排序,所以运行速度很快。请参阅下面的第二个代码:

带序的代码版本:

#include <iostream>
#include <vector>
#include <string>
#include <cmath>
#include <algorithm>
#include "omp.h"

using namespace std;

vector<int> dividors;
int NUMBER = 1000;

bool ifContains(vector<int> dividors, int dividedNumber)

    for(int i=0; i<dividors.size(); i++)
    
        if(dividors[i] == dividedNumber)
            return true;
    

    return false;


void doStuff()

    int sqr = (int) sqrt(NUMBER);
    int sqrp1 = sqr + 1;

    #pragma omp parallel
    
        #pragma omp for ordered
        for (int i = 1; i < sqrp1; i++)
        

            if (NUMBER % i == 0)
            
                #pragma omp ordered 
                
                    dividors.push_back(i);
                    if (!ifContains(dividors, i))
                        dividors.push_back(i);

                    int dividednumber = NUMBER / i;

                    if (!ifContains(dividors, dividednumber))
                        dividors.push_back(dividednumber);
                
            
        

    
    sort(dividors.begin(), dividors.end());  
    for (int i = 0; i < dividors.size(); i++)
    
        cout << dividors[i] << "\r\n";
    


int main()

    doStuff();
    return 0;

使用私有除数向量的代码版本

#include <iostream>
#include <vector>
#include <string>
#include <cmath>
#include <algorithm>
#include "omp.h"

using namespace std;

vector<int> dividors;
int NUMBER = 1000;

bool ifContains(vector<int> dividors, int dividedNumber)

    for(int i=0; i<dividors.size(); i++)
    
        if(dividors[i] == dividedNumber)
            return true;
    

    return false;


void doStuff()

    int sqr = (int) sqrt(NUMBER);
    int sqrp1 = sqr + 1;

    #pragma omp parallel
    
        vector<int> dividors_private;
        #pragma omp for nowait
        for (int i = 1; i < sqrp1; i++)
        

            if (NUMBER % i == 0)
            

                dividors_private.push_back(i);
                //printf("i %d\n", i);
                if (!ifContains(dividors_private, i))
                    dividors_private.push_back(i);

                int dividednumber = NUMBER / i;

                if (!ifContains(dividors_private, dividednumber))
                    dividors_private.push_back(dividednumber);
            
        
        sort(dividors_private.begin(), dividors_private.end());
        #pragma omp critical
        
            dividors.insert(dividors.end(), dividors_private.begin(), dividors_private.end());
        
    
    sort(dividors.begin(), dividors.end()); 
    for (int i = 0; i < dividors.size(); i++) 
    
        cout << dividors[i] << "\r\n";
    


int main()

    doStuff();
    return 0;

【讨论】:

【参考方案2】:

我在 gdb 中运行了您的代码,并且在调用 dividors.push_back(...) 时随机崩溃。这似乎是一种竞争条件,原因是您同时从多个线程更改 dividors 向量,从这个意义上说,std::vector 类不是线程安全的。见std::vector, thread-safety, multi-threading。

您要做的是确保没有线程更改向量,而另一个线程更改或读取它。这适用于在每个线程上对其进行排序。在#pragma omp single 中执行此操作,它只需要排序一次,尤其不需要同时从多个线程中排序。

【讨论】:

以上是关于运行方法并等待完成所有 for 循环 openmp的主要内容,如果未能解决你的问题,请参考以下文章

OpenMP 并行等待

在 OpenMP 中并行化嵌套循环并使用更多线程执行内部循环

使用 OpenMP 在 C、C++ 中并行化嵌套 for 循环的几种方法之间的区别

OpenMP 不在不同的线程中运行这个 for 循环,我该如何修复它

for循环和mysql节点如何等待所有查询完成处理视图

javascript:循环中如何等待方法完成了再继续?