2012-11-30 23 views
0

这是在F90中,但这个问题适用于任何支持OpenMP的语言。对于需要多个存储阵列的模拟代码结构数据的典型方式进行时间积分会(2维现在):告诉阵列的OpenMP线程部分是只读的

REAL, DIMENSION(imax,jmax,n_sub_timesteps) :: vars 

哪些随后将被类似更新:

DO J = 1, jmax 
    DO I = 1, imax 
    vars(I,J,2) = func(vars(:,:,1)) 
    END DO 
END DO 

根据我的经验,OpenMP不会实际并行化这些循环,因为它认为vars不是线程安全的。但对程序员来说,显然是这样的。

让我们假设对于进一步的实际情况,使vars线程本地将数据复制到它太昂贵。

那么,有没有办法轻轻提示(又名胁迫)OpenMP到不锁定vars,因为它可能不知道没有线程依赖性问题,但实际上没有?我知道有一些方法可以告诉它某些东西不是线程安全的并且需要锁定,但有没有一种方法可以指定反转而不为每个线程创建副本?

回答

3

看起来你错误的OpenMP自动并行化。我不知道进行数据锁定,除非明确通过引入CRITICAL部分或ATOMIC语句(或在并行区域结束了REDUCTION条款)告诉因此任何OpenMP实现的。 OpenMP编译器不要检查您的代码是否存在可能的数据依赖性,并阻止您并行运行 - 这完全由您决定。如果你想做不受保护的并发访问,你可以这样做,并且没有启用OpenMP的编译器会阻止你这样做。下面的代码将总是产生一个并行区域,并会分布在组中的线程之间的外环:

!$OMP PARALLEL DO PRIVATE(I) 
DO J = 1, jmax 
    DO I = 1, imax 
    vars(I,J,2) = func(vars(:,:,1)) 
    END DO 
END DO 
!$OMP END PARALLEL DO 

在另一方面,在大多数编译器内置自动parallelisers是非常保守和谨慎,通常如果没有程序员的明确提示,就不会并行处理像你这样的情况。这些提示通常采用编译器特定指令的形式(在Fortran中格式化为注释或在C/C++中作为编译指示)。例如英特尔Fortran支持!DEC$ PARALLEL指令,提示它忽略假定数据的依赖性在下面的指令循环:

!DEC$ PARALLEL 
DO J = 1, jmax 
    DO I = 1, imax 
    vars(I,J,2) = func(vars(:,:,1)) 
    END DO 
END DO 

许多编译重用他们的OpenMP的实现和运行时库,以实现自动并行化功能,因此通常使用OpenMP环境变量(如OMP_NUM_THREADS)来控制生成的可执行文件的运行。

如果您的并行OpenMP程序运行速度比预期慢,还有很多其他原因,主要与错误共享,缓存废弃,TLB垃圾回收,内存带宽限制,NUMA系统上的非本地内存访问有关,加载/存储到共享变量等等,所以它可能看起来像OpenMP是执行自动数据锁定,但它不。