2014-04-08 11 views
6

Ich habe in den letzten Tagen ein komisches Problem gekämpft. Wir erstellen einige Bibliotheken mit GCC 4.8, die einige ihrer Abhängigkeiten statisch verknüpfen - z. log4cplus oder boost. Für diese Bibliotheken haben wir Python-Bindings mit boost-python erstellt.Unterschied zwischen der Verbindung von OpenMP mit -fopenmp und -lgomp

Jedes Mal, wenn eine solche Bibliothek TLS verwendet (wie log4cplus bei der statischen Initialisierung oder stdlibC++ bei einer Ausnahme - nicht nur während der Initialisierungsphase), stürzte das Ganze in einem segfault ab - und jedes Mal die Adresse des Threads local Variable wurde 0.

Ich versuchte alles wie Neukompilieren, sicherzustellen, dass -fPIC verwendet wird, sicherzustellen, -tls-Modell = global-dynamische wird verwendet, etc. Kein Erfolg. Dann habe ich heute herausgefunden, dass der Grund für diese Abstürze unsere Art ist, OpenMP zu verlinken. Wir haben das mit "-lgomp" gemacht, anstatt nur "-fopenmp" zu verwenden. Seit ich das geändert habe, funktioniert alles gut - keine Abstürze, nichts. Fein!

Aber ich würde wirklich gerne wissen, was die Ursache des Problems war. Worin besteht der Unterschied zwischen diesen beiden Möglichkeiten, in OpenMP zu verlinken?

Wir haben eine CentOS 5 Maschine hier, wo wir eine GCC-4.8 in/opt/local/gcc48 installiert haben und wir sind auch sicher, dass die libgomp aus/opt/local/gcc48 verwendet wurde, genauso wie die libstdC++ von dort (DL_DEBUG benutzt).

Irgendwelche Ideen? Habe bei Google nichts gefunden - oder ich habe die falschen Schlüsselwörter verwendet :)

+0

-pthread oder -lpthread war da – duselbaer

+1

Kompilieren Sie mit '-v' und vergleichen Sie die Ausgabe ... –

+1

Das Hinzufügen von -v als Linker-Option zeigt, dass -fopenmp implizit am Ende ein -lgomp hinzufügt. Alles andere bleibt gleich. Ohne -fopenp habe ich "-lstdC++ -lm -lgcc_s -lpthread -lc -lgcc_s" und mit -fopenmp wird es "-lstdC++ -lm -lgomp -lgcc_s -lpthread -lc -lgcc_s". Ich sehe immer noch nicht den Grund für die Abstürze, weil alle diese Bibliotheken dynamisch verknüpft sind :( – duselbaer

Antwort

6

OpenMP ist ein Vermittler zwischen Ihrem Code und seiner Ausführung. Jede #pragma omp-Anweisung wird in Aufrufe ihrer entsprechenden OpenMP-Bibliotheksfunktion konvertiert, und alles ist da. Die Multithread-Ausführung (Starten von Threads, Verbinden und Synchronisieren von ihnen usw.) wird immer vom Betriebssystem (OS) gehandhabt. Alles OpenMP erledigt diese Low-Level-Betriebssystem-abhängigen Threading-Aufrufe für uns portabel in einer kurzen und süßen Schnittstelle.

Das Flag -fopenmp ist ein High-Level-Flag, das mehr als GCCs OpenMP-Implementierung (gomp) enthält. Diese Gomp-Bibliothek benötigt mehr Bibliotheken, um auf die Threading-Funktionalität des Betriebssystems zugreifen zu können. Auf POSIX-kompatiblen Betriebssystemen basiert OpenMP normalerweise auf pthread, das verknüpft werden muss. Es kann auch erforderlich sein, dass die Realtime Extension Library (librt) auf einigen Betriebssystemen funktioniert, während auf anderen nicht. Wenn Sie dynamisches Verknüpfen verwenden, sollte alles automatisch erkannt werden, aber wenn Sie -static angegeben haben, denke ich, dass Sie in die von Jakub Jelinek here beschriebene Situation gefallen sind. Aber heutzutage sollte pthread (und rt, falls benötigt) automatisch verknüpft werden, wenn -static verwendet wird.

Neben der Verknüpfung von Abhängigkeiten aktiviert das Flag -fopenmp auch einige Pragma-Anweisungsverarbeitung. Sie können im gesamten GCC-Code (wie here und here) sehen, dass ohne das Flag -fopenmp (das nicht nur durch Verknüpfung der Gomp-Bibliothek ausgelöst wird) mehrere Pragmas nicht in den entsprechenden OpenMP-Funktionsaufruf konvertiert werden. Ich habe gerade mit einem Beispielcode versucht, und sowohl -lgomp als auch -fopenmp erzeugen eine funktionierende ausführbare Datei, die mit denselben Bibliotheken verknüpft. Der einzige Unterschied in meinem einfachen Beispiel, dass die -fopenmp ein Symbol hat, das die -lgomp nicht hat: [email protected]@GOMP_4.0+ (Code here), die die Funktion ist, die den parallelen Abschnitt, der die von #pragma omp parallel in meinem Beispielcode angeforderten Gabeln ausführt, initialisiert. Daher hat die -lgomp-Version das Pragma nicht in einen Aufruf der OpenMP-Implementierung von GCC übersetzt. Beide erzeugten eine funktionierende ausführbare Datei, aber nur das Flag -fopenmp erzeugte in diesem Fall eine parallele ausführbare Datei.

Zum Abschluss wird -fopenmp benötigt, damit GCC alle OpenMP-Pragmas verarbeiten kann. Ohne es werden Ihre parallelen Abschnitte keinen Thread auszweigen, der je nach den Annahmen, auf denen Ihr innerer Code ausgeführt wurde, verheerenden Schaden anrichten könnte.

+0

Mit Ihrem Beispiel haben Sie (Kompilierung) der Quelle mit '-fopenmp' erstellt und dann Ihre' .o' in Verbindung mit '-fopenmp' /' -lgomp' verwendet? Wenn Sie benutze 'gcc -fopenmp example.c' es wird omp-pragma in kompilierung aktivieren und bibliothek in verbindung hinzufügen, aber einzelner kompilieren + link in form von' gcc -lgomp example.c' übergibt nicht die openmp-aktivierungsoption an kompilierung und pragma omp wird sein ignoriert. – osgx

+1

Ich mag mich irren, aber ich glaube, wir sagen das Gleiche? Ich schrieb: "Nur' -fopenmp "erzeugt eine parallele ausführbare Datei", während du etwas wie "-lgomp" geschrieben hast, erzeugt keine parallele ausführbare Datei ", oder habe ich etwas übersehen? (Wie ich geschrieben habe, werden Pragmas nicht zu einem Funktionsaufruf ohne '-fopenmp' konvertiert). Auf jeden Fall stimme ich mit dem überein, was Sie gesagt haben, und ich glaube, die Antwort sagt dasselbe. Vielleicht könnte der Wortlaut meiner Antwort besser sein ... – Soravux