2016-08-28 2 views
1

Je pense que mon problème est lié ou même identique au problème décrit here. Mais je ne comprends pas ce qui se passe réellement.sous-programme d'appel dans un environnement parallèle

J'utilise openMP avec le compilateur gfortran et j'ai la tâche suivante à faire: j'ai une distribution de densité F(X, Y) sur une surface à deux dimensions avec les coordonnées x et y X coordonnées Y. La matrice F a la taille Nx x Ny.

J'ai maintenant un ensemble de coordonnées Xp(i) et Yp(i) et j'ai besoin d'interpoler la densité F sur ces points. Ce problème est fait pour la parallélisation.

!$OMP PARALLEL DO DEFAULT(SHARED) PRIVATE(i) 
    do i=1, Nmax 

     ! Some stuff to be done here 

     Fint(i) = interp2d(Xp(i), Yp(i), X, Y, F, Nx, Ny) 

     ! Some other stuff to be done here 

    end do 
!$OMP END PARALLEL DO 

Tout est partagé à l'exception de i. La fonction interp2d effectue une interpolation linéaire simple.

Cela fonctionne très bien avec un fil, mais échoue avec multithreading. J'ai remonté le problème à la hunt -subroutine tirée de Numerical Recipes, qui est appelée par interp2d. Le hunt -subroutine calcule essentiellement l'indice ix tel que X(ix) <= Xp(i) < X(ix+1). Ceci est nécessaire pour obtenir le point de départ de l'interpolation.

Avec multithreading il arrive de temps en temps, que l'on obtient des fils de l'indice correct ix de hunt et le fil, qui appelle hunt obtient ensuite le même indice exact, même si Xp(i) est même pas proche de ce moment-là.

Je peux empêcher cela en utilisant l'environnement CRITICAL:

!$OMP PARALLEL DO DEFAULT(SHARED) PRIVATE(i) 
    do i=1, Nmax 

     ! Some stuff to be done here 

    !$OMP CRITICAL 
     Fint(i) = interp2d(Xp(i), Yp(i), X, Y, F, Nx, Ny) 
    !$OMP END CRITICAL 

     ! Some other stuff to be done here 

    end do 
!$OMP END PARALLEL DO 

Mais cela diminue l'efficacité. Si j'utilise par exemple trois threads, j'ai une moyenne de charge de 1,5 avec l'environnement CRITICAL. Sans avoir une moyenne de charge de 2,75, mais des résultats erronés et même parfois une erreur d'exécution SIGSEGV.

Ce qui se passe ici exactement? Il me semble que tous les threads appellent le même hunt -subroutine et s'ils le font en même temps il y a un conflit. Cela a-t-il du sens?

Comment puis-je empêcher cela?

+1

Il semble que le sous-programme 'hunt' ne soit pas thread-safe. Déplacez simplement votre directive 'critical' de l'appel à' interp2d' jusqu'à l'appel de 'hunt' dans' interp2d' (ou aussi bas que possible). – Gilles

+1

Pourriez-vous poster le code des routines 'interp2d' et' hunt'? Habituellement, lorsque vous avez besoin d'un 'critical' pour faire fonctionner un code, c'est parce que vous avez une ressource partagée (par exemple une variable) qui est lue et écrite par plusieurs threads en même temps. – smateo

+0

Je ne suis pas sûr si je peux poster le sous-programme de Recettes Numériques ici. Mais je posterai quelque chose de simplifié plus tard. Maintenant, je pense que tous les threads accèdent à la même pile et parfois, selon le temps d'exécution des routines, ils ne lisent pas les variables fictives dans le bon ordre à partir de la pile. Cela a-t-il un sens? Puis-je forcer chaque thread à avoir sa propre pile privée? – Sebastian

Répondre

1

La combinaison de déclaration variable et l'initialisation en Fortran 90+ a l'effet secondaire de donner la variable l'attribut SAVE.

integer :: i = 0 

est à peu près équivalent à:

integer, save :: i 

if (first_invocation) then 
    i = 0 
end if 

SAVE « D variables conservent leur valeur entre plusieurs appels de la routine et sont donc mises en oeuvre ultérieurement pour les variables statiques. Par les règles régissant les classes implicites de partage de données dans OpenMP, ces variables sont partagées à moins qu'elles ne soient listées dans une directive threadprivate.

mandats OpenMP que les compilateurs compatibles devraient s'appliquer la sémantique ci-dessus, même si la langue sous-jacente est Fortran 77.