Open Source im professionellen Einsatz
Linux-Magazin 05/2010
© Ariadna De Raadt, 123RF.com

© Ariadna De Raadt, 123RF.com

C++0x, Teil 2: Neues in der Standardbibliothek

Reichhaltiges Angebot

C++0x bringt nicht nur Veränderungen in der Kernsprache. Die Standardbibliothek der C++-Neuausgabe hat Multithreading, asynchrone Funktionsaufrufe, reguläre Ausdrücke und vieles mehr im Angebot.

654

Der demnächst fertige C++-Standard C++0x hat viel zu bieten - nicht nur auf Ebene der Kernsprache, die Teil 1 dieses Artikel behandelte [1]. Mit Bibliotheken fürs Threading, für reguläre Ausdrücke und zum Template Metaprogramming stößt die Sprache auch in neue Einsatzgebiete vor. Daneben runden Bibliotheken zu Smart Pointern, Containern und Funktions-Wrappern bereits vorhandene Konzepte in C++ ab, sodass sich C++0x im Ganzen deutlich reifer zeigt.

Eine der größten Herausforderungen, denen sich eine moderne Programmiersprache stellen muss, ist die Allgegenwart von Multicore-Prozessoren. Herb Sutter, Vorsitzender des ISO-C++-Standardisierungskomitees, wies bereits 2004 darauf hin, dass Software-Entwickler nicht mehr automatisch von schnelleren CPUs profitieren - sie müssen ihre Arbeitsweise an die Mehrkernprozessoren anpassen. Sutter: "The free lunch is over." [2]

Multithreading inklusive

C++0x begegnet der Mehrkern-Herausforderung unter anderem mit einem Memory-Modell in der Kernsprache. Ein solches Modell definiert, wie Threads auf Speicher interagieren und sich synchronisieren. Es liefert den Compiler-Bauern die Grundlage für Code-Optimierungen. Die recht anspruchsvollen Details rund um das neue Memory-Modell sowie die neuen atomaren Datentypen und Funktionen sind in der Artikelsammlung von Hans Böhm unter [3] nachzulesen.

Jenseits der Kernsprache, im Umgang mit der Threading-Bibliothek, gibt sich die neue Funktionalität schon vertrauter: C++0x besitzt die Threading-Bausteine, die aus anderen Bibliotheken bekannt sind. Der »std::thread« in Listing 1 wird über das Funktionsobjekt »Work()« parametrisiert und ausgeführt. Ein anschließendes »std::join« synchronisiert den neuen Thread mit dem Vater-Thread. Aber auch für das Lösen der Lebenszeit des neuen Thread vom Vater-Thread bietet C++0x Unterstützung.

Listing 1: Starten eines
Thread

01 class Work{
02 public:
03    void operator()(int i,std::string s,std::vector<double> v){ ... }
04 };
05 
06 std::thread t(Work(),42,"hello",std::vector<double>(23,3.141));
07 t.join();

Mutexe schaffen Ordnung

Mutexe helfen die Synchronisation gemeinsam genutzter Variablen zwischen Threads zu gewährleisten. Das Mutex in Zeile 5 von Listing 2 versucht das Lock in der Funktion »foo« 3 Millisekunden lang zu erhalten und führt die Funktion »process(data)« abhängig davon aus. Das »std::time_mutex« verwendet die neue Funktion »std::chrono«.

Mutexe sollte der Entwickler nicht direkt, sondern besser über den Wächter »std::unique_lock« einsetzen. Dieser Wächter bindet das Mutex in seinem Konstruktor und gibt es in seinem Destruktor automatisch wieder frei. Bekannt ist dieses C++-Idiom, eine kritische Ressource in einem Objekt zu kapseln, unter dem Namen RAII [4].

Neben einem nicht freigegebenen Lock sind Deadlocks [5] ein häufiges Problem bei Threads. Ein Deadlock kann entstehen, wenn mindestens zwei Threads die gleichen Locks in verschiedener Reihenfolge anfordern. Dagegen demonstriert Listing 3 ein probates Mittel, denn durch den Aufruf von »std::lock« in Zeile 4 erhält der aufrufende Thread entweder beide Locks (»a.m« und »b.m«) oder gar keines. Greifen die Threads auf eine gemeinsam genutzte Variable nur lesend zu, so genügt es, die Variablen beim Initialisieren vor konkurrierenden Zugriffen zu schützen. In Listing 4 stellt »std::once_flag« in Kombination mit »std::call_once« sicher, dass die Methode »createInstance« nur einmal ausgeführt wird, und dies vor allem Thread-sicher.

Dieser ganze Synchronisationsaufwand ist nicht notwendig, wenn jeder Thread seine eigene Kopie der Variablen besitzt. C++0x unterstützt zu diesem Zweck Thread-lokale Daten. Daneben gibt es Bedingungsvariablen, die die einfache Synchronisation von Threads durch Events erlauben. Den einfachen Umgang mit Threads kann man sehr schön in "Simpler Multithreading in C++0x" von Anthony Williams [6] nachlesen.

Listing 2: Mutex und
Wächter in Aktion

01 std::timed_mutex m;
02 my_class data;
03 
04 void foo(){
05   std::unique_lock<std::timed_mutex> lk(m,std::chrono::milliseconds(3));
06   if(lk) process(data);
07 }

Listing 3: Atomares Locken
mehrerer Locks

01 void foo(X& a,X& b){
02   std::unique_lock<std::mutex> lock_a(a.m,std::defer_lock);
03   std::unique_lock<std::mutex> lock_b(b.m,std::defer_lock);
04   std::lock(lock_a,lock_b);
05 
06   // do the whole work with a and b
07 }

Linux-Magazin kaufen

Einzelne Ausgabe
 
Abonnements
 
TABLET & SMARTPHONE APPS
Bald erhältlich
Get it on Google Play

Deutschland

Ähnliche Artikel

  • C++11

    Der Smart Pointer gilt als der klügste seiner Art in C++11. Sein Fachgebiet ist die elegante Garbage Collection, manchmal muss aber sein kleiner Bruder Weak Pointer mithelfen.

  • C++11

    Die neuen Smart Pointer in C++11 machen den Zugriff auf Ressourcen transparent und räumen hinter sich auf. Dieser Artikel stellt als ersten Vertreter den Unique Pointer vor.

  • C++11

    Klein, aber oho: Platziert ein Entwickler drei Punkte ("…") geschickt an der richtigen Stelle im C++-Code, entpacken die so genannten Variadic Templates ihre Argumente an Ort und Stelle.

  • C++11

    2014 ist ein besonderes Jahr für C++. Drei Jahre nach C++11 erfährt der Sprachstandard mit C++14 den letzten Feinschliff. Neben generischen Lambda-Funktionen und der vereinfachten Ermittlung des Rückgabetyps kann C++14 vor allem mit einem Feature punkten: Reader-Writer-Locks.

  • C++11

    Die Referenz-Wrapper bilden eine kleine, aber feine neue Bibliothek in C++11. Diese Objekte verhalten sich wie Referenzen, der Artikel erklärt die Details.

comments powered by Disqus

Ausgabe 10/2017

Digitale Ausgabe: Preis € 6,40
(inkl. 19% MwSt.)

Artikelserien und interessante Workshops aus dem Magazin können Sie hier als Bundle erwerben.