OpenMP while 循环 [英] OpenMP while loop

查看:73
本文介绍了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<<"	";
                    }
                    cout<<" 	 nit="<<nit<<"	 thread: "<<omp_get_thread_num();
                    cout<<endl;
                }
            } else{
                #pragma omp critical
                {
                    dit++;
                    cout<<"Discarded: "<<dit<<"
"<<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<<"	";
                }
          }
     } else {
          #pragma omp atomic update
          dit++;
     }
 }

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

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

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

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天全站免登陆