Der neue C++11 Standard Allgemeine Neuerungen und ... · PDF fileVisual Studio (2013) Teils...

Post on 04-Feb-2018

217 views 1 download

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