运行方法并等待完成所有 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 在 C、C++ 中并行化嵌套 for 循环的几种方法之间的区别