Threading Building Blocks - IPD Tichy

Transcription

Threading Building Blocks - IPD Tichy
Software Engineering für moderne parallele Plattformen
6. Parallelität in C/C++
Dipl.-Inform. Korbinian Molitorisz
M. Sc. Luis Manuel Carril Rodriguez
IPD Prof. Dr. Walter F. Tichy – Lehrstuhl für Programmiersysteme
KIT – Universität des Landes Baden-Württemberg und
nationales Forschungszentrum in der Helmholtz-Gemeinschaft
www.kit.edu
Agenda
Parallele Programmierung in C/C++
Allgemeines
Ausgewählte Bibliotheksansätze
Pthreads
Threading Building Blocks
OpenMP
2
06.06.2013
SEMPP 2013, Kapitel 6
IPD Prof. Dr. Walter F. Tichy
Lehrstuhl für Programmiersysteme
Allgemeines
Seit 2011 in C/C++ gibt es Unterstützung für Parallelität -> C++11
Ansätze zur Erweiterung:
Bibliotheken
Spracherweiterungen
3
06.06.2013
SEMPP 2013, Kapitel 6
IPD Prof. Dr. Walter F. Tichy
Lehrstuhl für Programmiersysteme
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
06.06.2013
SEMPP 2013, Kapitel 6
IPD Prof. Dr. Walter F. Tichy
Lehrstuhl für Programmiersysteme
Pthreads – Überblick (2)
Pthreads Schnittstelle enthält mehr als 60 Funktionen
Bezeichner beginnen mit pthread_
Typ
Beschreibung
pthread_
Basisfunktionen (z.B. create, …)
pthread_attr_
Fadenattribute (z.B. Scheduling, Priorität)
pthread_mutex_
Mutex-Variablen (z.B. init, lock, unlock)
pthread_mutexattr_
pthread_cond_
Mutex-Attribute (z.B. Mutex-Typ normal,
recursive, …)
Bedingungsvariablen („wait“, „signal“)
fadenspezifische Daten (erzeugt z.B.
pthread_key_
5
06.06.2013
SEMPP 2013, Kapitel 6
Datenschlüssel, der für alle Fäden sichtbar
ist)
IPD Prof. Dr. Walter F. Tichy
Lehrstuhl für Programmiersysteme
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
06.06.2013
SEMPP 2013, Kapitel 6
IPD Prof. Dr. Walter F. Tichy
Lehrstuhl für Programmiersysteme
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
06.06.2013
SEMPP 2013, Kapitel 6
IPD Prof. Dr. Walter F. Tichy
Lehrstuhl für Programmiersysteme
PThreads
Erzeugen von Fäden (2)
int pthread_create (
pthread_t
const pthread_attr_t
void pthread_attr_t
void
*tid,
*attr,
*(*start) (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
06.06.2013
SEMPP 2013, Kapitel 6
IPD Prof. Dr. Walter F. Tichy
Lehrstuhl für Programmiersysteme
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
06.06.2013
SEMPP 2013, Kapitel 6
IPD Prof. Dr. Walter F. Tichy
Lehrstuhl für Programmiersysteme
PThreads
Beitreten eines Fadens („Join“)
int pthread_join( pthread_t
void
Hauptfaden
thread,
**value_ptr);
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
06.06.2013
SEMPP 2013, Kapitel 6
IPD Prof. Dr. Walter F. Tichy
Lehrstuhl für Programmiersysteme
PThreads
Lebenszyklus eines Fadens
erzeugt
Warten beendet
ready
blocked
unterbrochen
Fertig zum
Ausführen,
wartet jedoch
auf Prozessor
Warten auf
Ressource
Für
Ausführung
eingeteilt
(scheduled)
running
Wird gerade
ausgeführt
Fertig, cancel
oder exit
terminated
11
06.06.2013
SEMPP 2013, Kapitel 6
Kann nicht
ausgeführt werden
(wartet z.B. auf
Mutex, E/A, ..)
Von start-Funktion
zurückgekehrt oder
pthread_exit oder cancel
IPD Prof. Dr. Walter F. Tichy
Lehrstuhl für Programmiersysteme
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
06.06.2013
SEMPP 2013, Kapitel 6
IPD Prof. Dr. Walter F. Tichy
Lehrstuhl für Programmiersysteme
PThreads
Mutex-Variablen (2)
Sperren / Entsperren
int pthread_mutex_lock( mutex );
int pthread_mutex_unlock( mutex );
13
06.06.2013
SEMPP 2013, Kapitel 6
IPD Prof. Dr. Walter F. Tichy
Lehrstuhl für Programmiersysteme
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;
// kritischer Abschnitt
pthread_mutex_unlock( &gMutex );
}
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);
06.06.2013
SEMPP 2013, Kapitel 6
IPD Prof. Dr. Walter F. Tichy
Lehrstuhl für Programmiersysteme
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
06.06.2013
SEMPP 2013, Kapitel 6
IPD Prof. Dr. Walter F. Tichy
Lehrstuhl für Programmiersysteme
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
06.06.2013
SEMPP 2013, Kapitel 6
IPD Prof. Dr. Walter F. Tichy
Lehrstuhl für Programmiersysteme
PThreads
Bedingungsvariablen
Prinzip
Faden 1
Faden 2
pthread_mutex_lock(&mtx);
while (state != 5) {
pthread_cond_wait(&cv,&mtx);
}
pthread_mutex_unlock(&mtx);
pthread_mutex_lock(&mtx);
state++;
pthread_cond_broadcast(&cv);
pthread_mutex_unlock(&mtx);
acquiriere mutex
while (negierte Bedingung ist wahr)
{wait auf Bedingungsvariable}
//else
Kritischer Abschnitt
gib mutex frei
17
06.06.2013
SEMPP 2013, Kapitel 6
Mutex wird automatisch
freigegeben, solange
der Faden wartet
IPD Prof. Dr. Walter F. Tichy
Lehrstuhl für Programmiersysteme
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
06.06.2013
SEMPP 2013, Kapitel 6
IPD Prof. Dr. Walter F.
18Tichy
Lehrstuhl für Programmiersysteme
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
06.06.2013
SEMPP 2013, Kapitel 6
IPD Prof. Dr. Walter F. Tichy
Lehrstuhl für Programmiersysteme
Threading Building Blocks
Überblick (1)
Intels Bibliotheksansatz zum parallelen Programmieren in
C/C++
Open Source (aktuelle Version: 4.1)
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
06.06.2013
SEMPP 2013, Kapitel 6
IPD Prof. Dr. Walter F. Tichy
Lehrstuhl für Programmiersysteme
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
06.06.2013
SEMPP 2013, Kapitel 6
IPD Prof. Dr. Walter F. Tichy
Lehrstuhl für Programmiersysteme
Threading Building Blocks
Überblick (3) – Historisches
1988
Languages
1995
Threaded-C
continuation tasks
task stealing
Cilk
space efficient scheduler
cache-oblivious algorithms
Pragmas
Chare Kernel
small tasks
STL
generic
programming
Libraries
OpenMP
fork/join
tasks
OpenMP taskqueue
while and recursion
JSR166
containers
STAPL
recursive ranges
2001
ECMA CLI
parallel iteration
classes
McRT
Intel Threading
Building Blocks
2006
“Key influences on design of Intel Threading Building Blocks”
Reinders, Intel Threading Building Blocks, O’Reilly, 2007
22
06.06.2013
SEMPP 2013, Kapitel 6
IPD Prof. Dr. Walter F. Tichy
Lehrstuhl für Programmiersysteme
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)
Konstrukte für Synchronisation
atomic, spin_mutex, spin_rw_mutex,
queuing_mutex, queuing_rw_mutex, mutex
Konstrukte zur Speicherallokation
cache_aligned_allocator
scalable_allocator
23
06.06.2013
SEMPP 2013, Kapitel 6
IPD Prof. Dr. Walter F. Tichy
Lehrstuhl für Programmiersysteme
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
06.06.2013
SEMPP 2013, Kapitel 6
IPD Prof. Dr. Walter F. Tichy
Lehrstuhl für Programmiersysteme
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
06.06.2013
SEMPP 2013, Kapitel 6
IPD Prof. Dr. Walter F. Tichy
Lehrstuhl für Programmiersysteme
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
06.06.2013
SEMPP 2013, Kapitel 6
IPD Prof. Dr. Walter F. Tichy
Lehrstuhl für Programmiersysteme
Vorbereitung zu Parallel For
Exkurs: Funktionsobjekte in C++ (2)
Beispiel: Akkumulation
template<class T> class AccumulateSum {
T accValue;
public:AccumulateSum(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);
cout << "Die Summe ist: "<<accSumObj.result() <<‘n’;
}
27
06.06.2013
SEMPP 2013, Kapitel 6
IPD Prof. Dr. Walter F. Tichy
Lehrstuhl für Programmiersysteme
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
06.06.2013
SEMPP 2013, Kapitel 6
IPD Prof. Dr. Walter F. Tichy
Lehrstuhl für Programmiersysteme
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]);
}}};
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
29
06.06.2013
SEMPP 2013, Kapitel 6
IPD Prof. Dr. Walter F. Tichy
Lehrstuhl für Programmiersysteme
Threading Building Blocks
Parallel For
#include "tbb/blocked_range.h"
• Repräsentiert
Intervall
#include
"tbb/parallel_for.h„
using
namespace
tbb;
• Allgemein
kann range
ein Intervall
rekursiv in zwei Teile aufteilen, bis eine
class
ChangeArray
{
vordefinierten
Größe erreicht
ist
int*
a;
(unterschiedliche
Arten der Aufteilung
public:
möglich)
ChangeArray(int* _a) {a=_a;}
• blocked_range:
eindimensionaler,
void operator()(const
blocked_range<int>& r) const {
gleichmäßig
aufgeteilter
Iterationsraum
for (int
i=r.begin();
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));
}
30
06.06.2013
SEMPP 2013, Kapitel 6
IPD Prof. Dr. Walter F. Tichy
Lehrstuhl für Programmiersysteme
Threading Building Blocks
Parallel For
#include "tbb/blocked_range.h" Aus ChangeArray wird Funktionsobjekt
erzeugt
#include "tbb/parallel_for.h„
using namespace tbb;
• Für jeden Arbeiterfaden werden durch
parallel_for separate Kopien des
class ChangeArray {
Funktionsobjekts mit unterschiedlichen
int* a;
Intervallgrenzen erzeugt
public:
ChangeArray(int* _a) {a=_a;}
void operator()(const blocked_range<int>& r) const {
for (int i=r.begin(); i!=r.end(); i++){
modifizierter
Foo(a[i]);
}}};
Schleifenrumpf aus
dem sequenziellen
Fall
void ChangeArrayParallel (int* a, int n) {
parallel_for(blocked_range<int>(0,n,AGrainSize),
ChangeArray(a));
}
31
06.06.2013
SEMPP 2013, Kapitel 6
IPD Prof. Dr. Walter F. Tichy
Lehrstuhl für Programmiersysteme
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
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).
32
06.06.2013
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“
IPD Prof. Dr. Walter F. Tichy
SEMPP 2013, Kapitel 6
vereinfachen. (vgl. auch C# Delegates)
Lehrstuhl für Programmiersysteme
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]
33
06.06.2013
SEMPP 2013, Kapitel 6
Tasks für „Work
Stealing“
IPD Prof. Dr. Walter F. Tichy
Lehrstuhl für Programmiersysteme
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
06.06.2013
SEMPP 2013, Kapitel 6
IPD Prof. Dr. Walter F. Tichy
Lehrstuhl für Programmiersysteme
Threading Building Blocks
Partitionierer
Partitionierer kann z.B. als optionaler dritter Parameter für
parallel_for verwendet werden
simple_partitioner (TBB 2.1 Standard)
Aufteilung bis zu kleinsten Teilen der Größe „grainsize“
auto_partitioner (TBB 2.2+ Standard)
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
06.06.2013
SEMPP 2013, Kapitel 6
IPD Prof. Dr. Walter F. Tichy
Lehrstuhl für Programmiersysteme
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
06.06.2013
SEMPP 2013, Kapitel 6
IPD Prof. Dr. Walter F. Tichy
Lehrstuhl für Programmiersysteme
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
06.06.2013
SEMPP 2013, Kapitel 6
IPD Prof. Dr. Walter F. Tichy
Lehrstuhl für Programmiersysteme
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;
Datei
// 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 );
Filter 1
Zeichenblöcke
einlesen
Filter 2
(kleingroß)
// Ausgabefilter für Dateiausgabe
MyOutputFilter output_filter( output_file );
pipeline.add_filter( output_filter );
// Führe Pipeline aus
pipeline.run( MyInputFilter::n_buffer );
pipeline.clear();
Filter 3
Dateiausgabe
fclose( output_file ); fclose( input_file );
...
38
06.06.2013
SEMPP 2013, Kapitel 6
IPD Prof. Dr. Walter F. Tichy
Lehrstuhl für Programmiersysteme
Threading Building Blocks
Fließbänder (4) – Beispiel
//“Mittlerer“ Filter
//transformiert Keinbuchstaben zu Großbuchstaben
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
39
06.06.2013
SEMPP 2013, Kapitel 6
IPD Prof. Dr. Walter F. Tichy
Lehrstuhl für Programmiersysteme
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
B
40
06.06.2013
SEMPP 2013, Kapitel 6
2
3
D
E
4
5
IPD Prof. Dr. Walter F. Tichy
Lehrstuhl für Programmiersysteme
Threading Building Blocks
Konstrukte zur Synchronisation
„schlafen“ beim
Warten
Fair
Reentrant
(bevorzugt länger
wartende Fäden)
(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
(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
06.06.2013
SEMPP 2013, Kapitel 6
IPD Prof. Dr. Walter F. Tichy
Lehrstuhl für Programmiersysteme
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
06.06.2013
SEMPP 2013, Kapitel 6
IPD Prof. Dr. Walter F. Tichy
Lehrstuhl für Programmiersysteme
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
06.06.2013
SEMPP 2013, Kapitel 6
IPD Prof. Dr. Walter F. Tichy
Lehrstuhl für Programmiersysteme
Threading Building Blocks
Aufspalten von Aufgaben
• Aufgaben müssen mit allocateMethoden Speicher reservieren
Parallele Version
• 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
06.06.2013
SEMPP 2013, Kapitel 6
IPD Prof. Dr. Walter F. Tichy
Lehrstuhl für Programmiersysteme
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
06.06.2013
SEMPP 2013, Kapitel 6
IPD Prof. Dr. Walter F. Tichy
Lehrstuhl für Programmiersysteme
Ausblick
Weitere Bibliotheken zur parallelen Programmierung in C/C++
C++11
In GCC ab 4.6
Einige Auszüge:
Explizite Faden-Erzeugung aus einer Funktion oder Lambda
Mutex (auch: rekursiv, zeitlich)
Conditon Variablen (wait)
Futures Operationen (parallel asynchrones Verhalten)
Atomic Datentypen und Operationen
46
06.06.2013
SEMPP 2013, Kapitel 6
IPD Prof. Dr. Walter F. Tichy
Lehrstuhl für Programmiersysteme
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
…
47
06.06.2013
SEMPP 2013, Kapitel 6
IPD Prof. Dr. Walter F. Tichy
Lehrstuhl für Programmiersysteme
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
48
06.06.2013
SEMPP 2013, Kapitel 6
IPD Prof. Dr. Walter F. Tichy
Lehrstuhl für Programmiersysteme
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
49
06.06.2013
SEMPP 2013, Kapitel 6
IPD Prof. Dr. Walter F. Tichy
Lehrstuhl für Programmiersysteme