[gelöst] C++: OpenMP Parallel
-
Du musst keine eigenen Kopierkonstruktoren schreiben, wenn du kein spezielles Verhalten benötigst. Die zählen auch zu den "special member functions".
Der Rest ist korrekt.
-
SeppJ schrieb:
Du musst keine eigenen Kopierkonstruktoren schreiben, wenn du kein spezielles Verhalten benötigst.
Das ist sicherlich der Knackpunkt, was man unter spezielles Verhalten versteht.
Wenn ich mich recht entsinne, dann begann für mich der ganze Lernprozess mit den verschiedenen Konstruktoren, weil ich
new
unddelete
verwendet hatte, also pointer.Bei der Verwendung eines Pointer im Kopierkonstruktor wird allerdings nur ein neuer Pointer erzeugt und der Inhalt hineinkopiert, was in diesem Falle die Addresse ist. Eine shallow copy, denn jetzt habe ich den Fall, dass zwei Pointer auf den gleichen Speicherbereich zeigen was z.B. zu einem dangling pointer führen kann?
Also möchte ich ein spezielles Verhalten: Ich möchte, dass der Speicherbereich, auf den der Pointer zeigt, neu angelegt wird und der Inhalt des Speicherbereichs (nicht nur die Addresse des Pointers) kopiert wird - eine deep copy. [1]
Vielleicht etwas salopp formuliert: Bei einem automatisch erstellten Kopier Konstruktor von einer shallow copy ausgehen und dann überlegen ob das reicht?
Gruß,
-- Klaus.[1] Oder ich umgehe die deep copy, indem ich mitzähle, wie viele Pointer auf einen Speicherbereich zeigen, um dangling Pointer zu verhindern. Das entspricht dann dem smart_pointer?
-
Alles richtig, jedoch ein ganz, ganz wichtiger Punkt wurde ausgelassen:
Wenn du new/delete brauchst, dann brauchst du meistens kein new/delete, sondern die Standardbibliothek. Meistens std::vector. Wenn du schon überlegst, selber Referenzen zu zählen, dann brauchst du ebenfalls die Standardbibliothek und zwar die Smartpointer daraus. Aber höchstwahrscheinlich brauchst du ebenfalls irgendeinen der fertigen Container, anstatt diesen aus Smartpointern nachzubauen.
Die ganzen Sachen aus der Standardbibliothek implementieren Kopien korrekt, du brauchst dich also wieder um nichts mehr zu kümmern.
http://en.cppreference.com/w/cpp/container
http://en.cppreference.com/w/cpp/memoryDas ist sicherlich der Knackpunkt, was man unter spezielles Verhalten versteht.
Das ist leicht zu erklären:
Standardverhalten des Defaultkonstruktors:
Defaultkonstruktor aller Elemente und Basisklassen aufrufenStandardverhalten des Kopierkonstruktors:
Kopierkonstruktor aller Elemente und Basisklassen aufrufenStandardverhalten des Zuweisungsoperators:
Zuweisungsoperator aller Elemente und Basisklassen aufrufenStandardverhalten des Destruktors:
Destruktor aller Elemente und Basisklassen aufrufenKann man sich merken, oder?
Zu beachten ist natürlich, dass diese Subfunktionen nicht unbedingt selber trivial sein müssen. Der Kopierkonstruktor eines vectors macht komplexe Dinge. Aber eine Klasse mit einem vector als Member braucht keinen eigenen Code im Kopierkonstruktor, um den vector zu kopieren, da schließlich der Kopierkonstruktors des vectors genommen wird, der schon alles richtig macht.
-
Man kann es sich auch merken, in dem man Basisklassen und Member als Subobjekte zusammenfasst - und dann machen die speziellen Memberfunktionen nichts weiter, als die Subobjekte zu verwalten - sprich kopieren, erzeugen, zuzuweisen oder zu zerstören.
-
Also so ganz habe ich es noch nicht raus.
Ich kriege bei der Übergabe zu
firstprivate
z.B. folgende Fehelermeldung:cppwrapper.cpp:46:47: error: use of deleted function ‘interpolation::interpolation(const interpolation&)’ In file included from cppwrapper.cpp:9:0: interpolation.h:11:8: note: ‘interpolation::interpolation(const interpolation&)’ is implicitly declared as deleted because ‘interpolation’ declares a move constructor or move assignment operator
Okay, ich habe noch keinen Copy Constructor eingerichtet, aber was heißt dieser explizite Hinweis, dass etwas
deleted
ist? DassOpen MP
nicht mit den Move und Assignement zurechtkommt?Edit:
Argh! Jetzt habe ich einen Copy Constructor eingerichtet und jetzt heißt esinterpolation.cpp:26:56: error: definition of implicitly-declareed 'interpolation::interpolation(const interpolation&)’
Gruß,
-- Klaus.
-
Jetzt habe ich einen Copy Constructor eingerichtet
Du musst dem armen Compiler aber sagen, dass er deinen nehmen soll, und nicht seinen. In dem du ihn in der Klasse deklarierst.
aber was heißt dieser explizite Hinweis, dass etwas deleted ist?
Einige spezielle Memberfunktionen werden als
deleted
definiert (sprich, als unbenutzbar definiert), weil andere definiert wurden.Sobald du einen Kopierkonstruktor definiert hast, darf der Compiler auch keinen Move-Konstruktor oder -Zuweisungsoperator definieren.
Et vice versa.Du solltest also in der entsprechenden Klasse den Kopierkonstruktor selbst als defaulted definieren:
interpolation(interpolation const&) = default; // In der Klasse
-
Vielleicht solltest du mal erst C++ lernen, bevor du mit Parallelisierung anfängst. Das Stichwort der "special member functions" ist doch schon öfters gefallen. Hast du das nie nachgeschlagen? Wenn du einen move-Konstruktor oder move-Zuweisungsoperator deklariert hast, dann wird kein Kopierkonstruktor automatisch erzeugt. Das ist auch gut so, denn wenn es irgendwie Sinn macht, einen eigenen move zu schreiben, dann ist ein automatisch erzeugter Kopierkonstruktor sicher nicht das, was du willst.
Genau das besagt die Fehlermeldung.Die Frage ist mal wieder, wieso du überhaupt einen move-Konstruktor definiert hast? Nutz doch die Standardbibliothek für dynamische Speicherverwaltung! Ganz besonders dann, wenn du nicht ganz sicher bist, was du tust. Du scheinst noch sehr unsicher auf dem Gebiet zu sein.
-
@Mods: Was gibt es hier zu löscheln?
OpenMP würde ich nicht mehr zu lernen empfehlen. Siehe zum Beispiel http://stackoverflow.com/questions/13837696/can-i-safely-use-openmp-with-c11 : Der Konsens ist, dass OpenMP als eine fortran-like Erweiterung für C++98 entworfen wurde. Weder C++03 noch C++11 sind unterstützt, es ist nicht einmal geplant, sie irgendwann zu unterstützen. OpenMP bedeutet ausschliesslich OpenMP, es gibt keine Verbindung zu anderen Threading-Modellen. Wenn OpenMP eine Berechtigung hat, dann als Nischenlösung für wissenschaftliche Simulationen ö.Ä.
Für "echtes" Threading gibt es C++11 oder TBB.
-
ommp schrieb:
@Mods: Was gibt es hier zu löscheln?
Weil dein vorheriger Beitrag nur sinnloses Gebashe ohne Bezug zum Thema war? Du hättest auch genau so gut "OpenMP ist doof!!!!!1111elf" schreiben können. Im Prinzip war es das, was du geschrieben hast, bloß mit leicht anderen Worten. Dein neuer Beitrag ist wenigstens produktiv, wenn auch nur mit sehr indirektem Bezug zum Thema, den lasse ich gerne stehen.
Wenn OpenMP eine Berechtigung hat, dann als Nischenlösung für wissenschaftliche Simulationen ö.Ä.
Ich ging bis jetzt davon aus, dass der TE genau das macht. Das sieht mir doch sehr nach einem schnellen C++-Lernen für ein bestimmtes Ziel aus, ohne Plan zum richtigen, tiefgründigen Verstehen. Zum Beispiel eine Diplom-/Master-/Bachelorarbeit, wo diese Vorgehensweise leider Standard ist, da man eben unter Zeitdruck ist.
-
SeppJ schrieb:
Ich ging bis jetzt davon aus, dass der TE genau das macht. Das sieht mir doch sehr nach einem schnellen C++-Lernen für ein bestimmtes Ziel aus, ohne Plan zum richtigen, tiefgründigen Verstehen. Zum Beispiel eine Diplom-/Master-/Bachelorarbeit, wo diese Vorgehensweise leider Standard ist, da man eben unter Zeitdruck ist.
Äh ja, das trifft es ziemlich gut. Momentan habe ich die Anforderung: Binden wir meinen C++ Code doch an einen mittels Open MP parallelisierten Fortran Code an.
Aber wenn ich es nicht genauer verstehen wollte, dann würde ich ja nicht so ausdauernd nachfragen, sondern so lange programmieren, bis die Compiler Warnungen verschwinden - oder?
Gruß,
-- Klaus.
-
Mh,
also diese vermeintlichen memory leaks sind bei Open MP eine kuriose Sache.Wenn ich ein vollkommen triviales Beispiel habe wie
#include <iostream> #include "omp.h" int main() { # pragma omp parallel { } return 0; }
dann sagt Valgrind schon, dass mit
malloc
was nicht stimmen würde und schließlich==6552== LEAK SUMMARY: ==6552== definitely lost: 0 bytes in 0 blocks ==6552== indirectly lost: 0 bytes in 0 blocks ==6552== possibly lost: 456 bytes in 3 blocks ==6552== still reachable: 1,748 bytes in 3 blocks ==6552== suppressed: 0 bytes in 0 blocks
Hä?
In dem Code passiert doch gar nichts. Das Erzeugen von threads sorgt schon für
still reachable
?Gruß,
-- Klaus.
-
Klaus82 schrieb:
In dem Code passiert doch gar nichts. Das Erzeugen von threads sorgt schon für
still reachable
?Ja. Was nicht weiter tragisch ist, denn da steht schließlich nicht "lost". Hier hat ein Programmierer bewusst den Speicher am Programmende nicht freigegeben. Was sein gutes Recht ist, denn er hat entweder Threads für Linux oder OpenMP für Linux programmiert (welcher Teil auch immer hier verantwortlich ist) und kann sich daher da drauf verlassen, dass das Betriebssystem sich allen Speicher bei Prozessende zurück holt.
-
Okay,
dann kann ich das Thema hoffentlich endlich abhaken.
Ich hatte mit dem nun (auch hoffentlich) richtigen Copy Constructor von Interpolation mittels
firstprivate
eine lokale Kopie an jeden Thread übergeben können.Und wenn ich mich bei dieser Fehlermeldung von Valgrind entspannen kann, dann ist scheinbar alles im grünen Bereich.
Dankeschöööööön!
#include <iostream> #include <vector> #include "interpolation.h" #include "omp.h" int main() { std::vector<double> x,y; for(unsigned int i = 0; i < 100; ++i) { x.push_back(static_cast<double>(i)); y.push_back(x[i] * x[i]); } interpolation inter(x,y); omp_set_num_threads(4); # pragma omp parallel firstprivate (inter) { double const number = omp_get_thread_num() + 0.5; # pragma omp critical { std::cout << inter(static_cast<double>(number)) << std::endl; } } return 0; }
Gruß,
-- Klaus.