Der neue C++11 Standard Allgemeine Neuerungen und ... · PDF fileVisual Studio (2013) Teils...
Transcript of Der neue C++11 Standard Allgemeine Neuerungen und ... · PDF fileVisual Studio (2013) Teils...
Der neue C++11 StandardAllgemeine Neuerungen und Nebenläufigkeit
Eine Präsentation von Sascha Koppfür Parallele Programmierung (G. Fröhlich)an der Hochschule Darmstadt (h_da)
Inhalt
1.Verbreitung
2.Fokus
3.Allgemeine Sprachfeatures
4.Nebenläufigkeit
5.Vorteile
6.Nachteile
7.Alternativen
8.Quellen
Verbreitung
● GCC vollständig, wird default mit zusätzlichen GNU-Extensions ab GCC-5
● Clang vollständig bis auf wenige Ausnahmen● Intel C++/Linux größtenteils vollständig● Intel C++/Windows Teils vollständig,
Nebenläufigkeit vollständig, außer Thread-Local Storage
● Visual Studio (2013) Teils vollständig, Nebenläufigkeit vollständig, außer Thread-Local Storage
Fokus
● Produktivität● Generalisierung● Nebenläufigkeit
Auto
● Compilezeitbestimmung von Datentypen an Hand von Rückgabewerten
auto x = getSomeData();
auto &x = getSomeData();
const auto x = getSomeData();
Default, Delete
class A{
public:
A() = default;
}
class B{
public:
B() = delete;
}
● Festlegen, ob es einen (Default-)Konstruktor gibt
● Dieser muss also nicht extra definiert werden
● default erzeugt ihn
● delete löscht ihn
constexpr
● Forcieren, dass eine Funktion oder Variable zur Compilezeit aufgelöst wird
● Compilieren schlägt fehl, wenn dies nicht möglich ist
constexpr int add(int a, int b)
{
return a+b;
}
const result = add(1, 3);
Raw-Literals
● Stringsequenzen, die Escapesequenzen ignorieren
● Sequenz "" wird zu " in Raw-Literals
std::string str = R"\No escapes/"
std::string str2 = R"Value is ""true"" !";
Datentypen fester Größe
● Interessant für Netzwerk- oder Embeddedanwendungen
● Least-Varianten zum sparen von Speicher● Fast-Varianten zum schnelleren berechnen● Unicode-Datentypen
int8_t, int16_t, int32_t, int64_t
char8_t, char16_t, char32_t
Static-Assert
● Ermöglicht das Testen von Bedingungen zur Compilezeit
● D.h. Vorabbestimmen, ob sich Code so verhält, wie man es möchte, solange er konstant/vorab berechenbar ist
static_assert(sizeof(int)==4, "Int is not 32bit on this system");
Smartpointer
● Übernommen aus TR1● Automatische Speicherverwaltung
std::unique_ptr<int> u = new int[300]; //Ersetzt auto_ptr, //unterstützt Arrays
std::shared_ptr<T> s = new T(); //Teilbar mit anderen
//Funktionen/Scopes
std::weak_ptr<T> w(s); //Schwache Referenz erstellen //(nützlich für Cachesysteme)
std::shared_ptr<T> sw = w.lock(); //Starke Referenz //erzeugen
STL-For Loops
● Iterieren über STL-Container
● Nicht verwechseln mit std::for_each(beg, end, func)
std:vector<int> v = {1, 2, 3};
for ( auto i : v) { //Über Objektkopie
doSomething(i);
}
for ( auto &i : v) { //Über Referenz
doSomething(i);
}
Lambda-Funktionen
● Inline-Definition von Funktionen
[captures] (params) -> retvaltype {
// code
}
[] Keine Übergabe
[=] Kopieren
[&] Referenzieren
[obj] obj kopieren
[&obj] obj referenzieren
[this] this-Pointer übernehmen
[this, &obj] mischen von Verschiedenen Angaben auch möglich
optionaloptional
Sonstiges
● Interne Änderungen am Speichersystem● Optimierung für nebenläufige Aufgaben● Garantiert das auf-/ bzw. absteigende Iterieren von
STL-Containern
● Viele weitere Neuerungen bzgl. Templates● Bspw. Variadic Templates, etc.
● Funktionen für Unicodebehandlung
Nebenläufigkeit
1.Grundlagen
2.Threads
3.Synchronisation
4.Thread-Local Storage
5.Atomics
6.Futures
Grundlagen
● C++11 verwendet eine vom Compiler bzw. Linker gebundene Threading-Bibliothek
● D.h. C++11-Threads sind Wrapper für solche● U.a. muss deswegen zumindest mit GCC eine
solche (hier: pthread) mitgelinkt werden● g++ -o <Ausgabe> --std=c++11 -lpthread <Eingabe>
● „--std=c++11“ legt hierbei den Sprachdialekt fest und muss bei jedem C++11-Programm angegeben werden
Threads
● Threads erlauben das nebenläufige Abarbeiten von Aufgaben in einem Prozess
● C++11 definiert hierzu die Klasse std::thread● Im Gegensatz zu betriebssystemspezifischen
Implementationen erlaubt der Standard mehrere Eingabeparameter von unterschiedlichen Datentypen
● C++11-Threads starten bei Instanziierung
std::thread
#include <thread>
//Erzeugen eines Threads
std::thread t(func, arg1 , arg2, ..., argn);
std::ref(arg) //Parameter als Referenz
t.join() //Warte auf Threadende
t.detach() //Lösen des Threads
//Warnung: Aktive Threadinstanzen, die ihr //Scope verlassen rufen std::terminate auf und //terminieren den Prozess, sofern diese nicht //gelöst wurden oder man ihr beenden abwartet
std::this_thread
● Enthält statische Funktionen, die für den aktuellen Thread gelten
● get_id() Threadid zurückgeben● yield() Rechenzeit freigeben● sleep_until(arg) Bis zu Zeitpunkt schlafen● sleep_for(arg) Für angegebene Zeit schlafen
Synchronisation
● C++11 kennt folgende Synchronisationsmechanismen:● Mutexe● Bedingungsvariablen
● Semaphoren sind nicht Teil des Standards
Mutexe
● Mutexe schützen kritische Datenbereiche vor multiplen Zugriffen
● Dazu definiert C++11 mehrere Typen von Mutex-Sperrvariablen
● Hier wird allerdings lediglich std::mutex, der Basistyp, behandelt
● Weitere speziellere Varianten sind:● std::timed_mutex● std::recursive_mutex● std::recursive_timed_mutex● std::shared_mutex
std::mutex
#include <mutex>
std::mutex m;
m.lock();
//critical section
m.unlock();
{
Std::lock_guard<std::mutex> _l(m);
//critical section
}
Bedingungsvariablen
● Bedingungsvariablen dienen als Synchronisationspunkte, um kritische Bereiche oder Ressourcen zu schützen
● Entgegengesetzt zu Mutexen, werden diese von anderen Threads benachrichtigt, wenn eine Ressource frei wird und ein oder mehrere wartende Threads geweckt
● Da Bedingungsvariablen an Bedingungen geknüpft sind ist es wichtig, diese nach dem wecken abzufragen und bedingt erneut zu warten, da wartende Threads eventuell extern durch das Betriebssystem geweckt werden könnten (Spurious Wakeup) und nicht, wie erwartet, durch andere Threads
● Hierzu gibt es std::condition_variable und für Spezielleres std::condition_variable_any (akzeptiert jeden Sperrvariablentyp)
std::condition_variable
#include <condition_variable>
#include <mutex>
std::mutex m; //global
std::condition_variable cv; //global
std::unique_lock<std::mutex> _l(m); //Wrapper für
while(!conditionmet) //Mutex
cv.wait(_l);
std::condition_variable
Veränderung signalisieren mit:
cv.notify_one();
cv.notify_all();
Thread-Local Storage
Abb. 1: Thread-Local Storage unter Microsoft Windows (Quelle: MSDN)
Thread-Local Storage
● Slotsystem für das Belegen und Anfordern threadlokalen Speichers
● Jedem Slot gehören mehrere Felder, die auf die eigentlichen Daten verweisen
● In C++11-Programmen werden thread-lokale Variablen über das thread_local Keyword spezifiziert und in der Regel im globalen Bereich deklariert
● Threads besitzen ihre eigenen privaten Kopien, dieser Variablen bzw. wird beim Zugriff in einen anderen Speicherbereich verwiesen
● Anwendung bspw. für Sitzungsinformationen oder Zufallszahlengeneratoren
std::atomic
● Atomare Variablen gehen sicher, dass keine inkonsistenten Zustände entstehen
● Alle Operationen (Zuweisen, In-/Dekrementieren, Herausladen, Vergleichen) sind atomar
#include <atomic>
std::atomic<int> aval(0);
int val = aval;
aval = val;
aval++;
Futures
● Futures sind ein Mechanismus, der Synchronisationspunkte an Variablen bindet
● Aufgaben (Tasks) werden asynchron gestartet und das Ergebnis später, wenn es benötigt wird abgefragt
● Ist das Ergebnis noch nicht vorhanden, wird blockiert
● Alternativ ist es möglich ein Versprechen (Promise) abzugeben und einem Thread zu übergeben, der dann weiter arbeitet, sobald die benötigten Daten zur Verfügung stehen
Futures
#include <future>
std::future<T> f; //Enthält ein zukünftiges Ergebnis
//Nicht blockierendes Aufrufen einer Funktion
//bzw. Spawnen eines neuen Threads/Tasks
f = std::async(std::launch::async, func, args...);
T val = f.get(); //Blockierendes Abfragen
//Teilen eines Futures für geteilte Verwendung
std::shared_future<T> sf = f.share();
Futures
#include <future>
std::promise<T> p; //Enthält das Versprechen ein //Ergebnis zu liefern
std::future<T> fp = p.get_future(); //Future //zurückliefern, dass das
//Ergebnis erhalten wird
p.set(val); //Das Versprechen erfüllen //fp wird also nicht mehr //blockieren
Vorteile
● Keine Verweise oder Marshalling von Daten notwendig, da Threads normale Parameter (int, char, etc.) annehmen und keine feste Form aufweisen müssen
● D.h. Funktionen selbst können auch als solche (nicht nur als Thread) aufgerufen werden und müssen nicht explizit angepasst werden
● Jede Instanz ist direkt an seine möglichen Funktionen gebunden (join, detach, etc.)
● Zugriff über gelinkte Threadingbibliothek auch möglich über native_handle Methode
Nachteile
● Keine Semaphoren● Vergleichsweise weniger Funktionalität als
bspw. boost● Keine Threadpools● Keine Möglichkeit einzelne Threads (unsauber)
zu terminieren● D.h. höherer Aufwand bei Planung
Alternativen
● Boost C++ Libraries
http://www.boost.org
● C# Concurrency Library● Java Concurrency Library
Quellen
● https://isocpp.org/wiki/faq/cpp11● http://en.cppreference.com/w/cpp/thread● Abb. 1:
http://msdn.microsoft.com/en-us/library/windows/desktop/ms686749%28v=vs.85%29.aspx