2016-02-18 14 views
0

我正在努力並行化一小部分具有循環和調用子程序的代碼。但結果與1個線程或2個線程不一致。我們不得不使用鎖嗎?OPENMP具有1或n個線程的可重複性

!$OMP parallel private(kk,j,i,k1,j1,i1,k2,j2,i2,ic,icm,xx,yy,ydatm),shared(undef,lt,ln,nd,xd,tgrd,ndaym) 
thread_id = OMP_GET_THREAD_NUM() 
num_threads = OMP_GET_NUM_THREADS() 
if(thread_id.eq.0) thread_id=thread_id+1 
start_no = (thread_id * ndaym/num_threads); 
end_no  = ((thread_id + 1) * ndaym/num_threads); 
xx(:)=undef 
yy(:,:)=undef 

!$OMP DO 
DO kk=start_no,end_no 

    do j=1,nlat 
    do i=1,nlon 
    ic=0 
    do k1=kk-nd,kk+nd 
    k2=k1 
    if(k2.lt.1)k2=1 
    if(k2.gt.ndaym)k2=ndaym 
    do j1=j-lt,j+lt 
     j2=j1 
     if(j2.lt.1)j2=1 
     if(j2.gt.nlat)j2=nlat 
     do i1=i-ln,i+ln 
     i2=i1 
     if(i2.lt.1)i2=1 
     if(i2.gt.nlon)i2=i2-nlon 
     ic=ic+1 
     yy(ic,:)=xdatm(i2,j2,k2,:) 
     yya(:) = yy(ic,:) 
     call funcmean(yya,xx(ic),1,nmem,nmem,undef) 
     if(k1.eq.kk.and.j1.eq.j.and.i1.eq.i) then 
     icm=ic 
     call funcsd(yya,1,nmem,nmem,undef,xx(ic),xd) 
     endif 
     enddo ! for i1  
    enddo ! for j1 
    enddo ! for k1 
    call funcens(xx,yy,tgrd,nmem,icm,undef,dist) 
    ydatm(i,j,kk,:)= dist(:) 
    enddo !for nlon 
enddo ! for nlat 
ENDDO !kk 

!$OMP end do 
deallocate(xx,yy) 
!$OMP end parallel 

任何人都可以提供一些線索嗎?

+1

它在我看來好像你正在試圖計算每個線程的外部do循環迭代的份額,以及所有那些計算'start_no'和'end_no'的東西。如果是這樣,你肯定錯過了關於OpenMP的一個要點,那就是編譯器爲你做的。在網絡上有很多很好的例子,即使在SO上也是如此,向您展示了Fortran + OpenMP中並行do循環的常見超級結構。 –

回答

2

我不知道該代碼的其餘部分是否正確(其實我甚至沒有嘗試讀它TBH),但一開始顯然是錯誤的:

!$OMP parallel private(kk,j,i,k1,j1,i1,k2,j2,i2,ic,icm,xx,yy,ydatm),shared(undef,lt,ln,nd,xd,tgrd,ndaym) 
thread_id = OMP_GET_THREAD_NUM() 
num_threads = OMP_GET_NUM_THREADS() 
if(thread_id.eq.0) thread_id=thread_id+1 
start_no = (thread_id * ndaym/num_threads); 
end_no  = ((thread_id + 1) * ndaym/num_threads); 

我會試着總結我在剛纔這個片段發現不對勁:

  • thread_idnum_threadsstart_noend_no沒有聲明private的變量。因此它們暗含shared,這顯然是非常錯誤的。爲避免這種基本陷阱,我強烈建議您在!$omp parallel指令中使用default(none)條款。這肯定會讓你頭痛不已。
  • if(thread_id.eq.0) thread_id=thread_id+1:好吧,假設thread_id已經(因爲它應該)宣佈private。之後,2個不同的線程(線程#0和#1)將具有相同的thread_id的值,即1。這意味着什麼?
  • 然後start_noend_no(甚至一次被宣佈爲private)使用thread_id的值計算,該值對於線程#0是假的。

試着先解決這些問題,看看它給了什麼。

對代碼其餘部分的額外檢查讓我懷疑deallocate(xx,yy)也可能是一個問題:除非分配在並行區域完成(這裏看起來並不是這樣,但仍然是可能的話),釋放應該移出它。

+0

@HighPerformanceMark公平,我沒有想過在這裏自動分配。但正如你所指出的那樣,語法無論如何都是虛假的。 – Gilles

+0

@HighPerformanceMark在第二次考慮時,即使採用正確的自動分配語法,如何將'undef'用於此目的,其中'xx'似乎是1D而'yy'是2D?這兩項任務中至少有一項無效,是嗎? – Gilles