2017-08-13 10 views
1

こんにちはを与えます。今度は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 

場合をI別のスレッドが異なっている必要があります異なるスレッドでfunbに対して同じ値を取っていることを私が見る大きなプログラムでOMP CRITICALを削除します。したがって、私の理解です: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はXL8、WL8のためにいくつかのデータであるが、サブルーチンが再び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

注釈は、私たちに機能のコードを示します。そして、関数をスレッドセーフなものにしてください*。これは以前何度もここで議論されていました。 –

+0

https://stackoverflow.com/questions/35347944/fortran-openmp-with-subroutines-and-functionsを参照してください。 –

+0

@VladimirF私はこの機能を追加しました。問題はプライベート/シェア変数の定義に関連していますか? –

答えて

2

THREADPRIVATE指令がない場合には、共通ブロック変数であります共有。並列セクション内で参照機能は、これはデータ競合の原因となり、そのような共通ブロックの変数を変更し、OpenMPの標準によって許可されていません。

コードは、暗黙の型とOpenMPの構文内で参照変数のほとんどのためのデータ共有属性の暗黙の仕様を使用しています。これらはコーディングスタイルの観点から賛同しています。表示されているコードには、間違いの可能性がある1つの可変スペルミスがあります。暗黙的な仕様が回避されていると回避されている可能性があります。

+0

感謝します。共通ブロックを正しく渡す方法はありますか?あなたが言っている可変スペルミスはどれですか? –

+0

threadprivate属性のドキュメントを参照してください。サンプルコードに 'xcn'と' xnc'という名前の変数があります。暗黙のタイピングを使わないでください!!!! – IanH