使用OpenMP显示flush direcitve:何时需要以及何时有用

Z b*_*son 8 openmp

我从未使用过的一个OpenMP指令,不知道何时使用flush(有和没有列表).

我有两个问题:

1.) When is an explicit `omp flush` or `omp flush(var1, ...) necessary?  
2.) Is it sometimes not necessary but helpful (i.e. can it make the code fast)?
Run Code Online (Sandbox Code Playgroud)

我无法理解何时使用显式刷新的主要原因是刷新是在许多指令(例如屏障,单个......)同步线程之后隐式完成的.例如,我不能看到使用flush的方式,而不是同步(例如with nowait)会有所帮助.

我知道不同的编译器可能omp flush以不同的方式实现.有些人可能会将列表与一个列表解释为没有(即刷新所有共享对象)OpenMP flush vs flush(list).但我只关心规范的要求.换句话说,我想知道flush原则上明确可能是必要的还是有用的.

编辑:我想我需要澄清我的第二个问题.让我举个例子.我想知道是否存在删除隐式刷新的情况(例如使用nowait)而是使用显式刷新而只是在某些共享变量上会更快(并且仍然给出正确的结果).类似于以下内容:

float a,b;
#pragma omp parallel
{
    #pragma omp for nowait // No barrier.  Do not flush on exit.
        //code which uses only shared variable a        
    #pragma  omp flush(a) // Flush only variable a rather than all shared variables.       
    #pragma omp for
       //Code which uses both shared variables a and b.
}
Run Code Online (Sandbox Code Playgroud)

我认为在第一个for循环之后代码仍然需要一个障碍,但是所有障碍都有一个隐含的冲洗,因此无法达到目的.是否有可能没有冲洗的屏障?

Mic*_*emm 15

flush指令告诉OpenMP编译器生成代码以使共享内存上的线程私有视图再次一致.OpenMP通常可以很好地处理这个问题,并为典型程序做正确的事情.因此,不需要冲洗.

但是,有些情况下OpenMP编译器需要一些帮助.其中一种情况是当您尝试实现自己的旋转锁定时.在这些情况下,您需要组合使用刷新才能使工作正常,否则旋转变量将不会更新.获得正确的冲洗顺序将是艰难的,并且非常非常容易出错.

一般建议不应使用刷新.如果有的话,程序员应该尽量避免使用列表(flush(var,...))进行刷新.有些人实际上在谈论在将来的OpenMP中弃用它.

在绩效方面,同花顺的影响应该是积极的,而不是积极的.由于它会导致编译器生成内存栅栏和额外的加载/存储操作,我希望它会减慢速度.

编辑:对于你的第二个问题,答案是否定的.OpenMP确保每个线程在需要时在共享内存上具有一致的视图.如果线程不同步,那么他们不需要更新他们在共享内存上的视图,因为他们没有看到任何"有趣"的变化.这意味着线程的任何读取都不会读取任何其他线程已更改的数据.如果是这种情况,那么你的程序中就会出现竞争条件和潜在的错误.为避免竞争,您需要进行同步(这意味着刷新以使每个参与线程的视图再次保持一致).类似的论点也适用于障碍.您可以使用障碍在计算并行区域时启动新纪元.因为你将线程保持在锁定状态,

BTW,OpenMP的保密的数据的线程,但它不具备对.因此,OpenMP编译器可能会将变量保留在寄存器中一段时间​​,这会导致它们与共享内存不同步.但是,对数组元素的更新通常很快会在共享内存中反映出来,因为线程的私有存储量通常很小(寄存器集,高速缓存,临时存储器等).OpenMP只能为您提供一些弱限制.实际的OpenMP实现(或硬件)可能与它希望的一样严格(例如,立即写回任何更改并一直刷新).

干杯,迈克尔