我有一段代码,它运行许多迭代,只有在满足条件时才保存迭代的结果。这自然地表达为一个while循环。我试图让代码并行运行,因为每个实现都是独立的。所以我有以下代码:
while(nit<avit){
#pragma omp parallel shared(nit,avit)
{
//do some stuff
if(condition){
#pragma omp critical
{
nit++;
\\save results
}
}
}//implicit barrier here
}
这很好用...但每次实现后都有一个屏障,这意味着如果并行块中的操作在某一次迭代中比其他操作花费更长时间,那么所有线程都会等待其完成,而不是继续下一次迭代。
有没有办法避免这个屏障,使线程继续工作?我要执行数千次迭代,所以多几次不会有影响(如果“nit”变量尚未在已运行的线程中递增)...
我尝试将其转换为并行for循环,但for循环中的自动递增使得“nit”变量失控。这是我的尝试:
#pragma omp parallel shared(nit,avit)
{
#pragma omp for
for(nit=0;nit<avit;nit++){
//do some stuff
if(condition){
\\save results
} else {
#pragma omp critical
{
nit--;
}
}
}
}
这段代码与预期一样在for循环中继续工作和运行,但是我的nit
变量却取决于不同线程在不同时间内的增加和减少,导致值无法预测。
我还尝试将for循环中的增量留空,但编译失败,或试图在代码中欺骗没有for循环增量,例如
...
incr=0;
for(nit=0;nit<avit;nit+=incr)
...
但是我的代码崩溃了...
有什么想法吗?
谢谢。
编辑:这里是一个在while循环中的工作最小化示例:
#include <random>
#include <vector>
#include <iostream>
#include <time.h>
#include <omp.h>
#include <stdlib.h>
#include <unistd.h>
using namespace std;
int main(){
int nit,dit,avit=100,t,j,tmax=100,jmax=10;
vector<double> Res(10),avRes(10);
nit=0; dit=0;
while(nit<avit){
#pragma omp parallel shared(tmax,nit,jmax,avRes,avit,dit) private(t,j) firstprivate(Res)
{
srand(int(time(NULL)) ^ omp_get_thread_num());
t=0; j=0;
while(t<tmax&&j<jmax){
Res[j]=rand() % 10;
t+=Res[j];
if(omp_get_thread_num()==5){
usleep(100000);
}
j++;
}
if(t<tmax){
#pragma omp critical
{
nit++;
for(j=0;j<jmax;j++){
avRes[j]+=Res[j];
}
for(j=0;j<jmax;j++){
cout<<avRes[j]/nit<<"\t";
}
cout<<" \t nit="<<nit<<"\t thread: "<<omp_get_thread_num();
cout<<endl;
}
} else{
#pragma omp critical
{
dit++;
cout<<"Discarded: "<<dit<<"\r"<<flush;
}
}
}
}
return 0;
}
我添加了usleep
部分来模拟一个线程的执行时间比其他线程长。如果你运行这个程序,所有的线程都必须等待第5个线程完成后才能开始下一轮执行。而我想要做的正是避免这种等待,也就是说,我希望其他线程在不等待5号线程完成的情况下继续执行下一次迭代。
nit
是否在某些东西中被访问,当多个线程同时拥有condition
时会发生什么,或者当一个线程正在执行某些东西时,nit
是否被多次更新... 这很困难,但为了得到一个好的、具体的答案,你必须创建一个[mcve]。 - Zulan