Software Engineering für moderne, parallele Plattformen. 6. Parallelität in C/C++ Dr. Victor Pankratius. Dr. Victor Pankratius



Ähnliche Dokumente
PThreads. Pthreads. Jeder Hersteller hatte eine eigene Implementierung von Threads oder light weight processes

Threads Einführung. Zustände von Threads

Softwaresysteme I Übungen Jürgen Kleinöder Universität Erlangen-Nürnberg Informatik 4, 2007 U9.fm

Shared-Memory Programmiermodelle

U9-3 Vergleich von Thread-Konzepten. U9-2 Motivation von Threads. U9-3 Vergleich von Thread-Konzepten (2) U9-1 Überblick

Monitore. Klicken bearbeiten

POSIX-Threads. Aufgabe 9 SP - Ü U10.1

Funktionen Häufig müssen bestimmte Operationen in einem Programm mehrmals ausgeführt werden. Schlechte Lösung: Gute Lösung:

I 7. Übung. I-1 Überblick. Besprechung Aufgabe 5 (mysh) Online-Evaluation. Posix Threads. Ü SoS I I.1

Objektorientierte Programmierung

Einführung in die Informatik für Naturwissenschaftler und Ingenieure (alias Einführung in die Programmierung)

1 Vom Problem zum Programm

Softwarelösungen: Versuch 4

Zählen von Objekten einer bestimmten Klasse

Vorkurs C++ Programmierung

Programmierkurs Java

OpenMP am Beispiel der Matrizenmultiplikation

Software Engineering. Zur Architektur der Applikation Data Repository. Franz-Josef Elmer, Universität Basel, HS 2015

U8 POSIX-Threads U8 POSIX-Threads

RTEMS- Echtzeitbetriebssystem

Nebenläufige Programmierung

Binäre Bäume. 1. Allgemeines. 2. Funktionsweise. 2.1 Eintragen

Java Kurs für Anfänger Einheit 5 Methoden

Einführung in die Programmierung

U8-1 Motivation von Threads. U8-2 Vergleich von Thread-Konzepten. U8-2 Vergleich von Thread-Konzepten (2) Motivation

Systeme 1. Kapitel 6. Nebenläufigkeit und wechselseitiger Ausschluss

Klausur in Programmieren

Prozeß P1 Prozeß P2. Zur Synchronisation stehen den beiden Prozessen binäre Semaphore und die beiden Funktionen

Intel Threading Building Blocks (TBB)

Dämon-Prozesse ( deamon )

Unterprogramme. Funktionen. Bedeutung von Funktionen in C++ Definition einer Funktion. Definition einer Prozedur

Objektorientierte Programmierung. Kapitel 12: Interfaces

Übung Grundlagen der Programmierung. Übung 03: Schleifen. Testplan Testergebnisse

Einführung in die Java- Programmierung

Tafelübung zu BS 2. Threadsynchronisation

Software Engineering Interaktionsdiagramme

Programmieren in Java

Programmieren in C. Felder, Schleifen und Fließkommaarithmetik. Prof. Dr. Nikolaus Wulff

Prinzipien Objektorientierter Programmierung

U6-1 Organisatories. U6-2 Motivation von Threads. U6-3 Vergleich von Thread-Konzepten. Organisatorisches

Universität Karlsruhe (TH)

Technische Dokumentation SilentStatistikTool

Tipps und Tricks zu Netop Vision und Vision Pro

Einführung in die C++ Programmierung für Ingenieure

Besprechung Aufgabe 5 (crawl) POSIX-Threads. Problem: UNIX-Prozesskonzept ist für viele heutige Anwendungen unzureichend

Erwin Grüner

.NET Code schützen. Projekt.NET. Version 1.0

Architektur Verteilter Systeme Teil 2: Prozesse und Threads

Applet Firewall und Freigabe der Objekte

Universität Karlsruhe (TH)

SEP 114. Design by Contract

Übungsblatt 3: Algorithmen in Java & Grammatiken

Deklarationen in C. Prof. Dr. Margarita Esponda

Objektbasierte Entwicklung

Automatisierung ( Fernsteuerung ) von Excel unter Microsoft Windows Tilman Küpper (tilman.kuepper@hm.edu)

Computerarithmetik ( )

Virtueller Seminarordner Anleitung für die Dozentinnen und Dozenten

Tutorium Rechnerorganisation

Grundlagen von Python

Verhindert, dass eine Methode überschrieben wird. public final int holekontostand() {...} public final class Girokonto extends Konto {...

2. Semester, 2. Prüfung, Lösung

Klausurteilnehmer. Wichtige Hinweise. Note: Klausur Informatik Programmierung, Seite 1 von 8 HS OWL, FB 7, Malte Wattenberg.

Einführung in die Programmierung (EPR)

Einführung in die Java- Programmierung

Einführung in die objektorientierte Programmierung mit Java. Klausur am 19. Oktober 2005

Programmieren. 10. Tutorium 4./ 5. Übungsblatt Referenzen

M. Graefenhan Übungen zu C. Blatt 3. Musterlösung

II. Grundlagen der Programmierung. 9. Datenstrukturen. Daten zusammenfassen. In Java (Forts.): In Java:

1 topologisches Sortieren

Prof. Dr. Uwe Schmidt. 21. August Aufgaben zur Klausur Objektorientierte Programmierung im SS 2007 (IA 252)

Tapps mit XP-Mode unter Windows 7 64 bit (V2.0)

Übungen zu Einführung in die Informatik: Programmierung und Software-Entwicklung: Lösungsvorschlag

Einfache und effiziente Zusammenarbeit in der Cloud. EASY-PM Office Add-Ins Handbuch

SEQUENZDIAGRAMM. Christoph Süsens

Einführung in die Programmierung

Objektorientierte Programmierung für Anfänger am Beispiel PHP

Betriebssysteme. Dipl.-Ing.(FH) Volker Schepper

Der Aufruf von DM_in_Euro 1.40 sollte die Ausgabe 1.40 DM = Euro ergeben.

Design by Contract with JML

Computeranwendung und Programmierung (CuP)

Native Zeichenketten (C-Strings)

Pthreads. David Klaftenegger. Seminar: Multicore Programmierung Sommersemester

Java: Vererbung. Teil 3: super()

Threads. Foliensatz 8: Threads Folie 1. Hans-Georg Eßer, TH Nürnberg Systemprogrammierung, Sommersemester 2015

2A Basistechniken: Weitere Aufgaben

Algorithmen & Datenstrukturen 1. Klausur

Java Kurs für Anfänger Einheit 4 Klassen und Objekte

Client-Server-Beziehungen

5 DATEN Variablen. Variablen können beliebige Werte zugewiesen und im Gegensatz zu

Datensicherung. Beschreibung der Datensicherung

Kapitel 4. Monitore und wechselseitiger Ausschluss

Alltagsnotizen eines Softwareentwicklers

Ziel, Inhalt. Programmieren in C++ Wir lernen wie man Funktionen oder Klassen einmal schreibt, so dass sie für verschiedene Datentypen verwendbar sind

Einrichtung des Cisco VPN Clients (IPSEC) in Windows7

Bedienung von BlueJ. Klassenanzeige

Algorithmen mit Python

4D Server v12 64-bit Version BETA VERSION

Fakultät Angewandte Informatik Lehrprofessur für Informatik

mywms Vorlage Seite 1/5 mywms Datenhaltung von Haug Bürger

Bitte verwenden Sie nur dokumentenechtes Schreibmaterial!

Transkript:

Software Engineering für moderne, parallele Plattformen 6. Parallelität in C/C++ IPD Tichy- Lehrstuhl für Programmiersysteme KIT die Kooperation von Forschungszentrum Karlsruhe GmbH und Universität Karlsruhe (TH)

Agenda Parallele Programmierung in C/C++ Allgemeines Ausgewählte Bibliotheksansätze Pthreads Threading Building Blocks OpenMP 2

Allgemeines In C/C++ gibt es momentan keine native Unterstützung für Parallelität Ansätze zur Erweiterung: Bibliotheken Spracherweiterungen Im Standardisierungsgremium von C++ wurden Erweiterungen im Hinblick auf Fäden und Sperren diskutiert ( C++0x Draft März 2009) 3

Pthreads Überblick (1) Bibliothek zum Arbeiten mit Fäden in C POSIX Threads IEEE-Standard (IEEE Std. 1003.1, 2004) Portable Operating System Interface Beschreibt Schnittstelle zwischen Applikationen und Betriebssystem Unix-Derivate halten sich mehr oder weniger daran Inzwischen auch für Windows erhältlich (Pthreads-win32) Verteilung von Fäden auf Prozessoren / Kerne sowie Ablaufplanung übernimmt das Betriebssystem 4

Pthreads Überblick (3) Pthreads Schnittstelle enthält mehr als 60 Funktionen Bezeichner beginnen mit pthread_ Typ pthread_ pthread_attr_ pthread_mutex_ pthread_mutexattr_ pthread_cond_ pthread_key_ Beschreibung Basisfunktionen (z.b. create, ) Fadenattribute (z.b. Scheduling, Priorität) Mutex-Variablen (z.b. init, lock, unlock) Mutex-Attribute (z.b. Mutex-Typ normal, recursive, ) Bedingungsvariablen ( wait, signal ) fadenspezifische Daten (erzeugt z.b. Datenschlüssel, der für alle Fäden sichtbar ist) 5

PThreads Erzeugen von Fäden (1) Jede Quelltextdatei, die die Pthreads-Bibliothek verwendet, muss pthread.h einbinden Initial hat das main()-programm einen Hauptfaden Alle anderen Fäden werden explizit vom Programmierer erzeugt pthread_create erzeugt und startet einen neuen Faden 6

PThreads Beispiel #include <pthread.h> #include <stdio.h> //Funktion, die ein Faden ausführen soll void* hello(void* id) { printf("%d: Hello world!\n", *((int*) id)); return 0; } int main(int argc, char* argv[]) { const int COUNT = 5; int i; pthread t thread[count]; int ids[count]; for (i = 0; i < COUNT; i++) { ids[i] = i; int retval = pthread create(&thread[i], NULL, hello, &ids[i]); if (retval) { perror("pthread_create failed"); return 1;} } for (i = 0; i < COUNT; i++) pthread_join(thread[i], NULL); return 0; } 7

PThreads Erzeugen von Fäden (2) int pthread_create ( pthread_t *tid, const pthread_attr_t *attr, void pthread_attr_t *(*start) (void *), void *arg); Erzeugt einen Faden, der die Funktion start mit Argument arg ausführt Aufruf ist asynchron implementierungsabhängig: Max. Anzahl erzeugbarer Fäden Argument attr spezifiziert optionale Attribute Z.B. für Scheduling, Priorität (Standard: NULL) Nach der Fadenerzeugung wird tid für Identifikation benutzt Fäden können selbst weitere Fäden erzeugen 8

PThreads Beenden von Fäden Verschiedene Möglichkeiten: Wenn main() endet, werden alle Fäden zerstört Faden kehrt von seiner Start-Routine zurück Faden ruft pthread_exit auf Achtung: Aufräumarbeiten werden nicht durchgeführt (z.b. können Dateien offen bleiben) Faden wird durch Aufruf von pthread_cancel durch einen anderen Faden abgebrochen Der gesamte Prozess wird durch den Aufruf von exec oder exit beendet 9

PThreads Beitreten eines Fadens ( Join ) int pthread_join( pthread_t thread, void **value_ptr); Hauptfaden pthread_create() Arbeiterfaden pthread_join() pthread_exit() der aufrufende Faden blockiert, bis der Faden mit der spezifizierten ID thread terminiert entsprechender Faden muss joinable sein val_ptr: Rückgabewert des beigetretenen Threads abfangen zurückgegebener Typ: (void *) NULL, wenn kein Rückgabewert erwartet wird 10

PThreads Lebenszyklus eines Fadens erzeugt Fertig zum Ausführen, wartet jedoch auf Prozessor ready Für Ausführung eingeteilt (scheduled) Warten beendet unterbrochen running Warten auf Ressource Wird gerade ausgeführt Fertig, cancel oder exit blocked Kann nicht ausgeführt werden (wartet z.b. auf Mutex, E/A,..) terminated Von start-funktion zurückgekehrt oder pthread_exit oder cancel 11

PThreads Mutex-Variablen (1) Mutex-Variable pthread_mutex_t mymutex; Muss vor Gebrauch initialisiert werden (zwei Möglichkeiten): int pthread_mutex_init( mutex, attr ); pthread_mutex_t mtx1 = PTHREAD_MUTEX_INITIALIZER //Makro Mutex-Variable wird vom aufrufenden Thread gehalten, bis dieser sie wieder freigibt ( unlock ) 12

PThreads Mutex-Variablen (2) Sperren / Entsperren int pthread_mutex_lock( mutex ); int pthread_mutex_unlock( mutex ); 13

PThreads Mutex-Variablen - Beispiel #define NUMTHREADS 4 pthread_mutex_t gmutex; int g_sum = 0; void *threadfunc(void *arg) { int mysum = bigcomputation(); pthread_mutex_lock( &gmutex ); g_sum += mysum; pthread_mutex_unlock( &gmutex ); } // kritischer Abschnitt main() { pthread_t hthread[numthreads]; pthread_mutex_init( &gmutex, NULL ); for (int i = 0; i < NUMTHREADS; i++) pthread_create(&hthread[i],null,threadfunc,null); 14 } for (int i = 0; i < NUMTHREADS; i++) pthread_join(hthread[i]); printf ( Global sum = %f\n, g_sum); Prof. Dr. W. F. Tichy, Dr. V. Pankratius, F. Otto

PThreads Mutex-Typen int pthread_mutexattr_settype( pthread_mutexattr_t *attr, int type); PTHREAD_MUTEX_NORMAL Faden, der bereits gesetzte Sperre noch einmal sperren will, erzeugt Verklemmung (Deadlock) trylock() verwenden. Verhalten undefiniert, wenn unlock bei nicht gesetzter Sperre durchgeführt wird bzw. wenn zweiter Faden Sperre eines anderen Fadens entsperren will. PTHREAD_MUTEX_ERRORCHECK Obige Operationen erzeugen Fehlermeldungen. PTHREAD_MUTEX_RECURSIVE Faden, der bereits Sperre hält, kann sie erneut akquirieren. Gleiche Anzahl von unlock-aufrufen nötig, um Sperre freizugeben. Rest der obigen Operationen erzeugt Fehlermeldung. PTHREAD_MUTEX_DEFAULT Im Standard: An implementation may map this mutex to one of the other mutex types 15

PThreads Bedingungsvariablen Bedingungsvariablen (Condition Variables) Signal / Wait Mechanismus in PThreads Warten, bis bestimmte Bedingung erfüllt ist Hintergrund: Effizient warten (ohne Polling) und Sperren in der Zwischenzeit aufgeben, um Fortschritt zu ermöglichen Wert der Bedingungsvariablen bestimmt, ob Faden warten muss oder mit Ausführung fortfahren darf 16

PThreads Bedingungsvariablen Prinzip Faden 1 Faden 2 pthread_mutex_lock(&mtx); while (state!= 5) { pthread_cond_wait(&cv,&mtx); } pthread_mutex_unlock(&mtx); acquiriere mutex while (negierte Bedingung ist wahr) {wait auf Bedingungsvariable} //else Kritischer Abschnitt gib mutex frei pthread_mutex_lock(&mtx); state++; pthread_cond_broadcast(&cv); pthread_mutex_unlock(&mtx); Mutex wird automatisch freigegeben, solange der Faden wartet 17

PThreads Bedingungsvariablen pthread_cond_t mycond; Initialisieren vor Gebrauch bzw. Zerstören einer Bedingungsvariable pthread_cond_init( cond, attr ) pthread_cond_destroy( cond ) pthread_cond_wait( cond, mutex ) Blockiert Faden, bis er ein entsprechendes Signal über eine Bedingungsvariable erhält (mutex wird währenddessen freigegeben) Muss mit gesperrter mutex-variablen aufgerufen werden (sonst undef.) pthread_cond_signal( cond ) Weckt mindestens einen der blockierten Fäden auf pthread_cond_broadcast( cond ) Alle blockierten Fäden werden aufgeweckt 18 18

PThreads Bedingungsvariablen Signale werden nicht gespeichert Wenn kein Faden wartet, ist ein zu dem Zeitpunkt gesendetes Signal verloren ( lost signal ) Ein Faden verhungert, wenn er auf ein Signal wartet, das nicht mehr gesendet wird 19

Threading Building Blocks Überblick (1) Intels Bibliotheksansatz zum parallelen Programmieren in C/C++ Open Source (aktuelle Version: 3.0) Ein TBB-Faden intern realisiert als Hüllklasse um plattformspezifischen Faden (Win32 API, PThreads) Konstrukte auf höherer Abstraktionsebene als PThreads, z.b. Parallele Schleifen Fließband (Pipeline) Aufgabenorientierter Parallelismus (Task Parallelism) 20

Threading Building Blocks Überblick (2) www.threadingbuildingblocks.org Bibliothek kann gleichzeitig auch mit anderen Bibliotheken oder OpenMP verwendet werden Im Folgenden einige ausgewählte Inhalte 21

Threading Building Blocks Überblick (3) Historisches 1988 1995 2001 Pragmas OpenMP fork/join tasks Languages Threaded-C continuation tasks task stealing Cilk space efficient scheduler cache-oblivious algorithms OpenMP taskqueue while and recursion Libraries JSR166 containers Chare Kernel STL small tasks generic programming STAPL recursive ranges 2006 ECMA CLI parallel iteration classes Intel Threading Building Blocks McRT 22 Key influences on design of Intel Threading Building Blocks Reinders, Intel Threading Building Blocks, O Reilly, 2007

Threading Building Blocks Überblick (4) Konstrukte parallel_for parallel_do parallel_reduce pipeline parallel_sort parallel_scan Container concurrent_hash_map concurrent_queue concurrent_vector Aufgabenabwickler (Task Scheduler) 23 Konstrukte für Synchronisation atomic, spin_mutex, spin_rw_mutex, queuing_mutex, queuing_rw_mutex, mutex Konstrukte zur Speicherallokation cache_aligned_allocator scalable_allocator

Threading Building Blocks Minimales Programmgerüst Initialisiert Task Scheduler #include tbb/task_scheduler_init.h using namespace tbb; int main() { task_scheduler_init init; return 0; } 24

Threading Building Blocks Container Die Container-Datenstrukturen in der Standard Template Library von C++ sind im parallelen Fall nicht anwendbar Threading Building Blocks stellt folgende Container zur Verfügung concurrent_hash_map Entwickler kann Hash- und Vergleichsoperationen selbst definieren concurrent_vector Größe dynamisch änderbar concurrent_queue Schlange mit blockierenden und nicht blockierende Operationen (pop bzw. pop_if_present) Aktives Warten beim Blockieren Wartezeiten sollten kurz sein! 25

Vorbereitung zu Parallel For Exkurs: Funktionsobjekte in C++ (1) Konstruktion einer Klasse die wie eine Funktion benutzt werden kann Überlädt operator() Operator für Methodenaufruf Kann Zustand kapseln (im Gegensatz zu reinen Funktionszeigern) Es kann mehrere Objektinstanzen geben class MyFunc {... public: void operator() (...) {...} }; MyFunc f; f(...); //ruft MyFunc::operator() auf 26

Vorbereitung zu Parallel For Exkurs: Funktionsobjekte in C++ (2) Beispiel: Akkumulation template<class T> class AccumulateSum { T accvalue; public: Sum(T initvalue) {accvalue=initvalue;} void operator()(t x) {accvalue +=x;} T result() const {return accvalue;} }; void test (list<double>& mylist) { AccumulateSum<double> accsumobj(0); //rufe accsumobj() für jedes Element der Liste auf for_each(mylist.begin(), mylist.end(), accsumobj); 27 } cout << "Die Summe ist: "<<accsumobj.result() << n ;

Threading Building Blocks Schleifen Beispiel: Sequenzielles Manipulieren eines Arrays void ChangeArraySerial (int* a, int n) { for (int i=0; i<n; i++) { Foo (a[i]); } } 28

Threading Building Blocks Parallel For #include "tbb/blocked_range.h" #include "tbb/parallel_for.h using namespace tbb; Aufgabe, die parallel ausgeführt werden soll class ChangeArray { int* a; public: ChangeArray(int* _a) {a=_a;} void operator()(const blocked_range<int>& r) const { for (int i=r.begin(); i!=r.end(); i++){ Foo(a[i]); }}}; 29 void ChangeArrayParallel (int* a, int n) { parallel_for(blocked_range<int>(0,n,agrainsize), ChangeArray(a)); } Rufe generische Funktion auf: parallel_for<range, body> hier mit: range blocked_range; body ChangeArray

Threading Building Blocks Parallel For 30 #include "tbb/blocked_range.h" #include Repräsentiert "tbb/parallel_for.h Intervall using Allgemein namespace kann range tbb; ein Intervall rekursiv in zwei Teile aufteilen, bis eine class vordefinierten ChangeArray Größe erreicht { ist int* (unterschiedliche a; Arten der Aufteilung public: möglich) ChangeArray(int* _a) {a=_a;} blocked_range: void operator()(const eindimensionaler, blocked_range<int>& r) const { gleichmäßig for (int aufgeteilter i=r.begin(); Iterationsraum i!=r.end(); i++){ über int Foo(a[i]); }}}; iteriere von 0 Kleinste bis n-1 Intervallgröße void ChangeArrayParallel (int* a, int n) { parallel_for(blocked_range<int>(0,n,agrainsize), ChangeArray(a)); }

Threading Building Blocks Parallel For 31 #include "tbb/blocked_range.h" #include "tbb/parallel_for.h using namespace tbb; class ChangeArray { int* a; public: ChangeArray(int* _a) {a=_a;} void operator()(const blocked_range<int>& r) const { }}}; for (int i=r.begin(); i!=r.end(); i++){ Foo(a[i]); void ChangeArrayParallel (int* a, int n) { parallel_for(blocked_range<int>(0,n,agrainsize), ChangeArray(a)); } Aus ChangeArray wird Funktionsobjekt erzeugt Für jeden Arbeiterfaden werden durch parallel_for separate Kopien des Funktionsobjekts mit unterschiedlichen Intervallgrenzen erzeugt modifizierter Schleifenrumpf aus dem sequenziellen Fall

Threading Building Blocks Parallel For und Lambda-Ausdrücke Anmerkung: Hätte C++ folgende Spracherweiterung, könnte man auf explizite Erzeugung von Funktionsobjekten verzichten //mit Lambda-Ausdruck 32 void ParallelApplyFoo(size_t n, int x) { parallel_for ( blocked_range<size_t>(0,n,10), <>(const blocked_range<size_t>& r) { for(size_t i=r.begin(); i<r.end();++i) Schleifenrumpf Foo(i,x); } Im C++ Standardkomittee vorgeschlagene Erweiterung für ); Lambda-Ausdrücke (vgl. Willcock, Lambda expressions and closures for C++, } 2006 und Järvi, Lambda Functions for C++0x, ACM SAC, 2008). Bedeutung von <> : Compiler soll automatisch den nachfolgenden Ausdruck in ein Funktionsobjekt konvertieren. Lambda-Ausdrücke würden generell die Übergabe von Code-Blöcken als Parameter erlauben und Schreibarbeit vereinfachen. (vgl. auch C# Delegates)

Threading Building Blocks Parallel For Prinzip der Gebietszerlegung - Aufgabenbaum Teile Intervall ( range ) auf [data, data+n[ [data, data+n/2[ [data+n/2, data+n[ rekursiv [data, data+n/k[ bis grainsize [data, data+grainsize[ Tasks für Work Stealing 33

Threading Building Blocks Partitionierer Spezifiziert Strategie für Ausführung von Schleifen parallel_for u.a. Konstrukte rufen Partitionierer auf, wenn range aufgeteilt werden soll jedes range-objekt ist mit einem partitioner-objekt assoziiert Partitionierer bestimmt wie Intervall aufgeteilt werden soll Gebietszerlegung Bis zu welcher Intervallgröße grainsize 34

Threading Building Blocks Partitionierer Partitionierer kann z.b. als optionaler dritter Parameter für parallel_for verwendet werden simple_partitioner (Standard) Aufteilung bis zu kleinsten Teilen der Größe grainsize auto_partitioner Gerade genug Aufteilungen, um Lastverteilung zu ermöglichen. Bei Bedarf werden neue Partitionen erzeugt. affinity_partitioner Wie auto_partitioner, jedoch mit besserer Cache-Affinität. Benachbarte Iterationen werden ggf. auf gleiche Arbeiterfäden verteilt. 35

Threading Building Blocks Fließbänder (1) Fließband (Pipeline): Besteht aus Sequenz von Filtern Auszug: class pipeline { public:... void add_filter( filter& f ); void run(size_t max_num_of_live_tokens); }; Kontrolliert die Anzahl der parallelen Tasks, die maximal existieren können Ein Filter f arbeitet sequenziell oder parallel mit mehreren Fäden Übergabe von Elementen zwischen Stufen erfolgt über Zeiger 36

Threading Building Blocks Fließbänder (2) Filter werden von Klasse filter geerbt Filter überschreibt virtual void* operator()( void * item ); Diese Methode wird von der Pipeline aufgerufen, um innerhalb eines Filters ein Element zu verarbeiten Parameter item zeigt auf das Element, das verarbeitet werden soll Der Rückgabewert zeigt auf das Element, das der nächsten Stufe übergeben werden soll Beispiel mit dreistufiger Pipeline: Lese Datei ein, transformiere Kleinbuchstaben in Großbuchstaben, schreibe Ergebnis in Datei 37

Threading Building Blocks Fließbänder (3) Beispiel...//FILE* input_file = fopen(inputfilename,"r");...//file* output_file = fopen(outputfilename,"r"); // Create the pipeline tbb::pipeline pipeline; // Erzeuge Eingabefilter (lese Datei ein, generiere Strom) MyInputFilter input_filter( input_file ); pipeline.add_filter( input_filter ); // Verarbeitungsfilter (transf. zu Großbuchstaben) MyTransformFilter transform_filter; pipeline.add_filter( transform_filter ); // Ausgabefilter für Dateiausgabe MyOutputFilter output_filter( output_file ); pipeline.add_filter( output_filter ); Datei Filter 1 Zeichenblöcke einlesen Filter 2 (klein groß) Filter 3 Dateiausgabe 38 // Führe Pipeline aus pipeline.run( MyInputFilter::n_buffer ); pipeline.clear(); fclose( output_file ); fclose( input_file );...

Threading Building Blocks Fließbänder (4) Beispiel // Mittlerer Filter //transformiert Keinbuchstaben zu Großbuchstaben 39 class MyTransformFilter: public tbb::filter { public: MyTransformFilter(); void* operator()( void* item ); //überschreibe Methode };... Konstruktor etc.... Operator() bekommt Zeiger auf Block von Zeichen und liefert einen Zeiger auf konvertiertem Block, der der nächsten Stufe übergeben werden soll. void* MyTransformFilter::operator()( void* item ) { MyBuffer& b = *static_cast<mybuffer*>(item); // konvertiere Puffer zu Großbuchstaben return &b; } Explizite Typkonvertierung, die zur Übersetzungszeit geprüft wird Semantik: Speicher, worauf item zeigt, wird als MyBuffer benutzt

Threading Building Blocks Fließbänder (5) Die Bibliothek unterstützt zur Zeit nur lineare Fließbänder Nicht-lineare Fließbänder könnten behelfsmäßig mit Hilfe einer topologischen Sortierung der Stufen durch linearer Fließbänder realisiert werden A 1 C 3 D 4 B 2 E 5 40

Threading Building Blocks Konstrukte zur Synchronisation Fair (bevorzugt länger wartende Fäden) Reentrant (Bei Rekursion anwendbar) mutex BS abhängig Nein Ja spin_mutex Nein Nein Nein queuing_mutex Ja Nein Nein spin_rw_mutex Nein Nein Nein queuing_rw_mutex Ja Nein Nein schlafen beim Warten (sonst Schleife) Scoped Locking -Muster wird benutzt Sperre in Wächterklasse Kein explizites Freigeben, Destruktor der Wächterklasse gibt Sperre automatisch frei Sicher beim Auslösen von Ausnahmen 41

Threading Building Blocks Atomare Operationen atomic<t> bietet atomare Operationen auf Typ T = x Lese Wert von x x = Schreibe Wert von x und gib ihn zurück x.fetch_and_store(y) Setze y=x und liefere alten x-wert x.fetch_and_add(y) Setze x+=y und liefere alten x-wert x.compare_and_swap(n,z) Wenn x==z, setze x=n; liefere in beiden Fällen alten x-wert zurück Interne Implementierung bildet atomare Operationen auf native, atomare Prozessorbefehle ab Vordefinierte Abbildungen für verschiedene Prozessor-Plattformen Z.B. compare_and_swap... mov rax,r8 lock cmpxchg [rcx],dl ret... 42

Threading Building Blocks Aufspalten von Aufgaben Illustration am Beispiel // Fibonacci sequenziell long SerialFib( long n ) { if( n<2 ) return n; else return SerialFib(n-1)+SerialFib(n-2); } 43

Threading Building Blocks Aufspalten von Aufgaben Parallele Version Aufgaben müssen mit allocate- Methoden Speicher reservieren Erzeugt Wurzel des Aufgabenbaums Konstruktor von FibTask long ParallelFib( long n ) { long sum; FibTask& a = *new(task::allocate_root()) FibTask(n,&sum); task::spawn_root_and_wait(a); return sum; } Ausführen und warten bis fertig Anmerkung: Hier steht Demonstration des Task-Konzepts im Vordergrund. Es gibt effizientere Möglichkeiten, Fibonacci-Zahlen zu berechnen. 44

Threading Building Blocks Aufspalten von Aufgaben class FibTask: public task { public: const long n; long* const sum; FibTask( long n_, long* sum_ ):n(n_), sum(sum_) {} task* execute() { if( n<cutoff ) { *sum = SerialFib(n); } else { long x, y; FibTask& a = *new( allocate_child() ) FibTask(n-1,&x); FibTask& b = *new( allocate_child() ) FibTask(n-2,&y); set_ref_count(3); spawn( b ); spawn_and_wait_for_all( a ); //starte a, warte auf *sum = x+y; //alle Kinder, d.h. a,b } return NULL; }}; 45

Ausblick Weitere Bibliotheken zur parallelen Programmierung in C/C++ Boost (www.boost.org) Einige Auszüge: Klasse boost::thread erzeugt und verwaltet Faden Fäden können zu Gruppen hinzugefügt werden Sperren Konzepte Lockable: Sperre exklusiv für einen Faden Timed lockable: Blockierendes Warten auf Sperre kann zeitlich begrenzt werden SharedLockable: Wie z.b. bei Lese-Schreib-Sperre (mehrere Fäden können gleichzeitig lesen, aber nur einer schreiben) UpgradeLockable: Von gemeinsamer Nutzung einer Sperre auf exklusive Nutzung Barrieren Bedingungsvariablen 46

Ausblick Weitere Bibliotheken zur parallelen Programmierung in C/C++ QtConcurrent (trolltech.com) Konzepte auf niedriger Abstraktionsebene (Sperren, Semaphore, ) Konzepte auf höherer Abstraktionsebene QtConcurrent::map() wendet Funktion parallel auf mehrere Elemene an QtConcurrent::mappedReduced() nach map wird Ergebnis mit Reduktionsoperation zu einem einzigen Ergebnis verdichtet QtConcurrent::filter() benutzt Filterfunktion um Elemente zu entfernen QtConcurrent::filteredReduced() gefiltertes Ergebnis Ergebnis wird mit Reduktionsoperation zu einem einzigen Ergebnis verdichtet QtConcurrent::run() führt eine Funktion in einem neuen Faden aus QFuture wie Futures QFutureWatcher Überwachen einer QFuture 47

Ausblick Weitere Bibliotheken zur parallelen Programmierung in C/C++ GNU libstdc++ parallel mode Parallelisierte Algorithmen der Standard Template Library Z.B. Suche, Sortieren, numerische Algorithmen, Im gcc V 4.3 parallel mode bereits enthalten In Karlsruhe entstanden 48