2017-08-13 176 views
1

嗨我正在嘗試在不同的線程中做一個循環。現在在do循環中我調用一個函數,它再次調用一些子例程並添加到總和中。現在,如果我並行封閉do循環,它會給出隨機結果,但是我發現如果將該函數置於CRITICAL環境中,它會給出正確的結果。但是這會花費更多的CPU時間,並不會提高速度。我用一個小測試程序進行了測試,並檢查我的邏輯是否正確。然而,在一個大的程序中(我不能在這裏發表)只有當我將函數調用放在CRITICAL中時纔有效。 下面我給測試程序:(我的測試程序的工作,並在大程序中,我看到funb沒有正確採取不同的線程,除非它處於臨界環境卻給出正確的結果)OpenMP調用函數給出了錯誤的結果

 sum=0d0 
!$OMP PARALLEL PRIVATE(i,j,sum1,xcn,fun) 
     ithrd=OMP_GET_THREAD_NUM() 
!$OMP DO 
     do i=1,5 
     sum1=0d0 
     do j=1,3 
      xcn=i+j+xx 
!$OMP CRITICAL 
     fun=funb(xnc) 
     write(*,*)fun 
!$OMP END CRITICAL 
     sum1=sum1+fun 
     enddo 
     enddo 
!$OMP END DO 
!$OMP CRITICAL 
     sum=sum+sum1 
!$OMP END CRITICAL 
!$OMP END PARALLEL 
     write(*,*)sum 

如果我在大程序中刪除OMP CRITICAL我發現不同的線程在不同的線程中對funb採用相同的值,這應該是不同的。因此,我的理解是:在PARALLEL節中調用的函數有一些限制。如果有人能夠澄清這個問題,我會很感激。

功能funb給出爲:

 COMPLEX*16 FUNCTION FUNB(ZAA) 

    IMPLICIT COMPLEX*16 (A-H,O-Z) 
    real*8 X1,X2 
    COMMON/ZVAR/ZA 
    COMMON/XVAR/X1,X2 
    ZA=ZAA 
    call myinvini 
    call myinvc(x2,fout) 
    funb=fout 
    RETURN 
    END 

myinvini是WL8,×18一些數據,但再次myinvc是子程序:

subroutine myinvc(x,f2) 
    complex*16 dir,dirc,sta,ss,ssc,cn,cnc,f2,ff,ffc,func 
    complex*16 f22,ans 
    integer igauss,inte,l,m 
    double precision x,range,phi,w,z,zz,zr 
    double precision st,st0,zint,xbl,a,b,dli,sli 
    double precision cpar,zero 
    double precision xl8,wl8,xl32,wl32 
    dimension zint(51) 
    COMMON/iinte/inte 
    complex*16 cbeta 
    common /wgauss/ xl8(8),wl8(8),xl32(32),wl32(32) 
    common /ccpar/ cpar 

    include 'constants.h' 
    igauss = 8 
    zero=0.0d0 
    range=201.0d0 
    phi=3.0d0/4.0d0*pi 
    dir=dcmplx(dcos(phi),dsin(phi)) 
    dirc=dcmplx(dcos(phi),-dsin(phi)) 
    sta=dcmplx(cpar,zero) 
    st =dexp(dlog(range)/dble(inte)) 
    st0=1.0d0 
    zint(1)=zero 
    do 11 l=1,inte  
    st0 =st0*st 
    zint(l+1)=st0-1.0d0 
    11 continue 

    ss=dcmplx(zero,zero) 
    ssc=dcmplx(zero,zero) 
    xbl=dlog(x) 

    do 23 l=1,inte ! inte=5 
    a=zint(l) 
    b=zint(l+1) 
    dli=(b-a)/2.d0 
    sli=(b+a)/2.d0 

    do 24 m=1,igauss 
    if(igauss.eq. 8) w=wl8(m) 
    if(igauss.eq.32) w=wl32(m) 
    if(igauss.eq. 8) zz=xl8(m) 
    if(igauss.eq.32) zz=xl32(m) 
    z =dli*zz+sli 
    cn=sta+z*dir 
    cnc=sta+z*dirc 

    ff=func(cn) 
    ffc=func(cnc) 

    ss=ss+ff*dir*exp(-xbl*cn)*w*dli 
    ssc=ssc+ffc*dirc*exp(-xbl*cnc)*w*dli 
    24 continue 
    23 continue 
    f2=(ss+ssc) 
    return 
    end 
+0

Pleaae向我們展示函數的代碼。請關於什麼使得函數*線程安全*。這在之前曾多次討論過。 –

+0

查看https://stackoverflow.com/questions/35347944/fortran-openmp-with-subroutines-and-functions –

+0

@VladimirF我已添加該功能。問題與私人/共享變量的定義有關嗎? –

回答

2

在沒有threadprivate指令的,公共塊變量是共享。並行部分內部引用的函數修改了這樣一個公共塊變量,這將導致數據競爭,並且openmp標準不允許這樣做。

該代碼對openmp結構中引用的大多數變量使用隱式鍵入和隱式指定數據共享屬性。從編碼風格的角度來看,這些正在悄然興起。所示的代碼有一個可能的變量拼寫錯誤,如果避免了隱含的規格,這可能會被避免。

+0

感謝您的解釋。有什麼辦法可以正確通過公共塊嗎?哪一個是你所指的變量拼寫錯誤? –

+0

查看有關threadprivate屬性的文檔。您的示例代碼中包含名爲'xcn'和'xnc'的變量。不要使用隱式輸入! – IanH

相關問題