OpenMP while循环 [英] OpenMP while loop

查看:256
本文介绍了OpenMP while循环的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个运行多次迭代的代码,只有在满足条件的情况下,迭代的结果才会被保存.这自然表示为while循环.我试图使代码并行运行,因为每个实现都是独立的.所以我有这个:

I have a code that runs many iterations and only if a condition is met, the result of the iteration is saved. This is naturally expressed as a while loop. I am attempting to make the code run in parallel, since each realisation is independent. So I have this:

while(nit<avit){
    #pragma omp parallel shared(nit,avit)
    {
        //do some stuff
        if(condition){
            #pragma omp critical
            {
                nit++;
                \\save results
            }
        }
    }//implicit barrier here
}

,这很好用...但是每次实现之后都有一个障碍,这意味着,如果我在并行块中执行的工作在一次迭代中比其他迭代花费更长的时间,那么我所有的线程都在等待它完成,而不是继续进行下一个迭代.

and this works fine... but there is a barrier after each realization, which means that if the stuff I am doing inside the parallel block takes longer in one iteration than the others, all my threads are waiting for it to finish, instead of continuing with the next iteration.

有没有一种方法可以避免这种障碍,从而使线程继续工作?我平均要进行数千次迭代,因此不会影响其他迭代(以防万一nit变量在已经运行的线程中没有增加)...

Is there a way to avoid this barrier so that the threads keep working? I am averaging thousands of iterations, so a few more don't hurt (in case the nit variable has not been incremented in already running threads)...

我试图将其转换为并行的for,但是for循环中的自动递增使nit变量变得疯狂.这是我的尝试:

I have tried to turn this into a parallel for, but the automatic increment in the for loop makes the nit variable go wild. This is my attempt:

#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变量采用了不可预测的值...正如人们可能在不同时间不同线程对它的增加和减少所期望的那样.

and it keeps working and going around the for loop, as expected, but my nit variable takes unpredictable values... as one could expect from the increase and decrease of it by different threads at different times.

我也尝试过将for循环中的增量留空,但它无法编译,或者试图欺骗我的代码以使for循环中没有增量,例如

I have also tried leaving the increment in the for loop blank, but it doesn't compile, or trying to trick my code to have no increment in the for loop, like

...
incr=0;
for(nit=0;nit<avit;nit+=incr)
...

但是我的代码崩溃了...

but then my code crashes...

有什么想法吗?

谢谢

这是while循环中代码的最小工作示例:

Here's a working minimal example of the code on a while loop:

#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个完成.

I added the usleep part to simulate one thread taking longer than the others. If you run the program, all threads have to wait for thread 5 to finish, and then they start the next run. what I am trying to do is precisely to avoid such wait, i.e. I'd like the other threads to pick the next iteration without waiting for 5 to finish.

推荐答案

您基本上可以遵循与此问题相同的概念,略有不同以确保不会并行写入avRes:

You can basically follow the same concept as for this question, with a slight variation to ensure that avRes is not written to in parallel:

int nit = 0;
#pragma omp parallel
while(1) {
     int local_nit;
     #pragma omp atomic read
     local_nit = nit;
     if (local_nit >= avit) {
          break;
     }

     [...]

     if (...) { 
          #pragma omp critical
          {
                #pragma omp atomic capture
                local_nit = ++nit;
                for(j=0;j<jmax;j++){
                    avRes[j] += Res[j];
                } 
                for(j=0;j<jmax;j++){
                    // technically you could also use `nit` directly since
                    // now `nit` is only modified within this critical section
                    cout<<avRes[j]/local_nit<<"\t";
                }
          }
     } else {
          #pragma omp atomic update
          dit++;
     }
 }

它也适用于关键区域,但原子效率更高.

It also works with critical regions, but atomics are more efficient.

还有另一件事需要考虑,rand()不应在并行上下文中使用.请参阅此问题.对于C ++,请使用<random>中的私有(即在并行区域内定义)随机数生成器.

There's another thing you need to consider, rand() should not be used in parallel contexts. See this question. For C++, use a private (i.e. defined within the parallel region) random number generator from <random>.

这篇关于OpenMP while循环的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆