Ich denke mein Problem ist verwandt oder sogar identisch mit dem beschriebenen Problem here. Aber ich verstehe nicht, was tatsächlich passiert.Unterroutine in paralleler Umgebung aufrufen
Ich verwende OpenMP mit dem gfortran Compiler und ich habe die folgende Aufgabe zu tun: Ich habe eine Dichteverteilung F(X, Y)
auf einer zweidimensionalen Fläche mit x-Koordinaten und X
Y
y-Koordinaten. Die Matrix F
hat die Größe Nx
x Ny
.
Ich habe jetzt eine Reihe von Koordinaten Xp(i)
und Yp(i)
und ich muss die Dichte F
auf diese Punkte interpolieren. Dieses Problem wurde für die Parallelisierung gemacht.
!$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
Alles ist geteilt außer i
. Die Funktion interp2d
führt eine einfache lineare Interpolation durch.
Das funktioniert gut mit einem Thread aber schlägt mit Multithreading fehl. Ich verfolgte das Problem auf die hunt
-Unterroutine aus Numerical Recipes, die von interp2d
aufgerufen wird. Die hunt
-Unterroutine berechnet grundsätzlich den Index ix
so, dass X(ix) <= Xp(i) < X(ix+1)
. Dies wird benötigt, um den Startpunkt für die Interpolation zu erhalten.
Mit ihm Multithreading passiert ab und zu, dass ein Threads den richtigen Index ix
von hunt
und den Faden bekommt, die hunt
nächste bekommt exakt die gleichen Index aufruft, obwohl Xp(i)
bis zu diesem Zeitpunkt nicht einmal in der Nähe ist.
Ich kann dies verhindern, indem die CRITICAL
-Umgebung:
!$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
Aber dies die Effizienz verringert. Wenn ich zum Beispiel drei Threads verwende, habe ich einen Lastdurchschnitt von 1,5 mit der CRITICAL
Umgebung. Ohne habe ich einen Lastdurchschnitt von 2,75, aber falsche Ergebnisse und manchmal sogar einen SIGSEGV
Laufzeitfehler.
Was genau passiert hier? Es scheint mir, dass alle Threads die gleiche hunt
-subroutine aufrufen und wenn sie es gleichzeitig tun, gibt es einen Konflikt. Ist das sinnvoll?
Wie kann ich das verhindern?
Es sieht so aus, als wäre das 'hunt'-Unterprogramm nicht Thread-sicher. Verschieben Sie einfach Ihre 'critical' Direktive weg von dem Aufruf zu' interp2d' runter zum Aufruf 'jagen' innerhalb von 'interp2d' (oder so niedrig wie möglich). – Gilles
Könnten Sie den Code der Routinen 'interp2d' und' hunt' posten? Normalerweise, wenn Sie ein 'critical' benötigen, damit ein Code funktioniert, liegt das daran, dass Sie eine gemeinsam genutzte Ressource (z. B. eine Variable) haben, die von mehreren Threads gleichzeitig gelesen und geschrieben wird. – smateo
Ich bin mir nicht sicher, ob ich das Unterprogramm von Numerical Recipes hier veröffentlichen kann. Aber ich werde später etwas vereinfachtes veröffentlichen. Mittlerweile denke ich, dass alle Threads auf den gleichen Stapel zugreifen und manchmal, abhängig von der Ausführungszeit der Routinen, lesen sie nicht die Dummy-Variablen in der richtigen Reihenfolge vom Stapel. Macht das irgendeinen Sinn? Kann ich jeden Thread zwingen, einen eigenen privaten Stack zu haben? – Sebastian