Sie sind auf Seite 1von 52

Übung Grundlagen der

Betriebssysteme (GBS)
Tafelübung 5: Synchronisation
Daniel Lohmann, Björn Fiedler
05t-sync 2018-12-14

Institute for Systems Engineering


System- und Rechnerarchitektur (SRA)

Wintersemester 2018

https://sra.uni-hannover.de/Lehre/WS18/V_GBS
Überblick: Tafelübung 5: Synchronisation

5 Tafelübung 5: Synchronisation
5.1 Threads
5.2 Schnittstelle
5.3 Koordinierung
5.4 Formatierte Eingabe
5.5 Aufgabe 5: patric
05t-sync 2018-12-14
Motivation von Threads

UNIX-Prozesskonzept (Ausführungsumgebung mit einem Aktivitätsträger)


für viele heutige Anwendungen unzureichend
keine parallelen Abläufe innerhalb eines logischen Adressraums auf
Multiprozessorsystemen
typische UNIX-Server-Implementierungen benutzen die fork-Operation, um
einen Server-Prozess für jeden Client zu erzeugen
Verbrauch unnötig vieler System-Ressourcen
zur besseren Strukturierung von Problemlösungen sind oft mehrere
Aktivitätsträger innerhalb eines Adressraums nützlich
05t-sync 2018-12-14

© dl,bf GBS (WS 18) 5 Tafelübung 5: Synchronisation | 5.1 Threads 5–3


Motivation von Threads

UNIX-Prozesskonzept (Ausführungsumgebung mit einem Aktivitätsträger)


für viele heutige Anwendungen unzureichend
keine parallelen Abläufe innerhalb eines logischen Adressraums auf
Multiprozessorsystemen
typische UNIX-Server-Implementierungen benutzen die fork-Operation, um
einen Server-Prozess für jeden Client zu erzeugen
Verbrauch unnötig vieler System-Ressourcen
zur besseren Strukturierung von Problemlösungen sind oft mehrere
Aktivitätsträger innerhalb eines Adressraums nützlich

Lösung: bei Bedarf weitere Aktivitätsträger in einem UNIX-Prozess erzeugen


05t-sync 2018-12-14

© dl,bf GBS (WS 18) 5 Tafelübung 5: Synchronisation | 5.1 Threads 5–3


Arten von Threads

User-Threads
Realisierung auf Anwendungsebene
Systemkern sieht nur einen Kontrollfluss
+ Erzeugung von Threads extrem billig
– Systemkern hat kein Wissen über diese Threads
in Multiprozessorsystemen keine parallelen Abläufe möglich
wird ein User-Thread blockiert, sind alle User-Threads blockiert
Scheduling zwischen den Threads schwierig
05t-sync 2018-12-14

© dl,bf GBS (WS 18) 5 Tafelübung 5: Synchronisation | 5.1 Threads 5–4


Arten von Threads

User-Threads
Realisierung auf Anwendungsebene
Systemkern sieht nur einen Kontrollfluss
+ Erzeugung von Threads extrem billig
– Systemkern hat kein Wissen über diese Threads
in Multiprozessorsystemen keine parallelen Abläufe möglich
wird ein User-Thread blockiert, sind alle User-Threads blockiert
Scheduling zwischen den Threads schwierig
Kernel-Threads
+ Gruppe von Threads nutzt gemeinsam die Betriebsmittel eines Prozesses
+ jeder Thread ist als eigener Aktivitätsträger dem Betriebssystemkern bekannt
05t-sync 2018-12-14

– Kosten für Erzeugung erheblich geringer als bei Prozessen, aber erheblich
teuerer als bei User-Threads

© dl,bf GBS (WS 18) 5 Tafelübung 5: Synchronisation | 5.1 Threads 5–4


Arten von Threads

Umschaltungskosten (“Gewichtsklasse”)
Kosten für Umschaltung zwischen Threads hängt maßgeblich von der
Anzahl der Adressraumwechsel ab.
Adressraum

Prozesse
Kern-

Scheduler
Adressraum
Benutzer-
05t-sync 2018-12-14

© dl,bf GBS (WS 18) 5 Tafelübung 5: Synchronisation | 5.1 Threads 5–5


Arten von Threads

Umschaltungskosten (“Gewichtsklasse”)
Kosten für Umschaltung zwischen Threads hängt maßgeblich von der
Anzahl der Adressraumwechsel ab.

Kernel-Threads
(1:1)
Adressraum

Prozesse
Kern-

Scheduler Scheduler
Adressraum
Benutzer-
05t-sync 2018-12-14

© dl,bf GBS (WS 18) 5 Tafelübung 5: Synchronisation | 5.1 Threads 5–5


Arten von Threads

Umschaltungskosten (“Gewichtsklasse”)
Kosten für Umschaltung zwischen Threads hängt maßgeblich von der
Anzahl der Adressraumwechsel ab.

Kernel-Threads User-Threads
(1:1) (1:many)
Adressraum

Prozesse
Kern-

Scheduler Scheduler Scheduler


Adressraum
Benutzer-
05t-sync 2018-12-14

Scheduler

© dl,bf GBS (WS 18) 5 Tafelübung 5: Synchronisation | 5.1 Threads 5–5


Arten von Threads

Umschaltungskosten (“Gewichtsklasse”)
Kosten für Umschaltung zwischen Threads hängt maßgeblich von der
Anzahl der Adressraumwechsel ab.

Kernel-Threads User-Threads Mischung


(1:1) (1:many) (many:many)
Adressraum

Prozesse
Kern-

Scheduler Scheduler Scheduler Scheduler


Adressraum
Benutzer-
05t-sync 2018-12-14

Scheduler Scheduler

© dl,bf GBS (WS 18) 5 Tafelübung 5: Synchronisation | 5.1 Threads 5–5


Überblick: Tafelübung 5: Synchronisation

5 Tafelübung 5: Synchronisation
5.1 Threads
5.2 Schnittstelle
5.3 Koordinierung
5.4 Formatierte Eingabe
5.5 Aufgabe 5: patric
05t-sync 2018-12-14
Pthreads-Schnittstelle

Thread erzeugen
int pthread_create(pthread_t *thread, const pthread_attr_t *attr,
void *(*start_routine)(void *), void *arg);

thread Thread-ID (Ausgabeparameter)


attr Modifizieren von Attributen des erzeugten Threads (z. B. Stackgröße). NULL
für Standardattribute.
Nach der Erzeugung führt der Thread die Funktion startec_routine mit
Parameter arg aus
Im Fehlerfall wird errno nicht gesetzt, aber ein Fehlercode als Ergebnis
zurückgeliefert.
Um perror(3) verwenden zu können, muss der Rückgabewert erst in der errno
gespeichert werden.
05t-sync 2018-12-14

© dl,bf GBS (WS 18) 5 Tafelübung 5: Synchronisation | 5.2 Schnittstelle 5–7


Pthreads-Schnittstelle

Thread erzeugen
int pthread_create(pthread_t *thread, const pthread_attr_t *attr,
void *(*start_routine)(void *), void *arg);

thread Thread-ID (Ausgabeparameter)


attr Modifizieren von Attributen des erzeugten Threads (z. B. Stackgröße). NULL
für Standardattribute.
Nach der Erzeugung führt der Thread die Funktion startec_routine mit
Parameter arg aus
Im Fehlerfall wird errno nicht gesetzt, aber ein Fehlercode als Ergebnis
zurückgeliefert.
Um perror(3) verwenden zu können, muss der Rückgabewert erst in der errno
gespeichert werden.
05t-sync 2018-12-14

Eigene Thread-ID ermitteln


pthread_t pthread_self(void);
Die Funktion kann nie fehlschlagen.

© dl,bf GBS (WS 18) 5 Tafelübung 5: Synchronisation | 5.2 Schnittstelle 5–7


Pthreads-Schnittstelle

Thread beenden (bei Rücksprung aus start_routine oder):


void pthread_exit(void *retval)
Der Thread wird beendet und retval wird als Rückgabewert zurück geliefert
(siehe pthread_join(3) )
05t-sync 2018-12-14

© dl,bf GBS (WS 18) 5 Tafelübung 5: Synchronisation | 5.2 Schnittstelle 5–8


Pthreads-Schnittstelle

Thread beenden (bei Rücksprung aus start_routine oder):


void pthread_exit(void *retval)
Der Thread wird beendet und retval wird als Rückgabewert zurück geliefert
(siehe pthread_join(3) )

Auf Thread warten, Ressourcen freigeben und Rückgabewert abfragen:


int pthread_join(pthread_t thread, void **retvalp)
Wartet auf den Thread mit der Thread-ID thread und liefert dessen
Rückgabewert über retvalp zurück.
05t-sync 2018-12-14

© dl,bf GBS (WS 18) 5 Tafelübung 5: Synchronisation | 5.2 Schnittstelle 5–8


Pthreads-Schnittstelle

Thread beenden (bei Rücksprung aus start_routine oder):


void pthread_exit(void *retval)
Der Thread wird beendet und retval wird als Rückgabewert zurück geliefert
(siehe pthread_join(3) )

Auf Thread warten, Ressourcen freigeben und Rückgabewert abfragen:


int pthread_join(pthread_t thread, void **retvalp)
Wartet auf den Thread mit der Thread-ID thread und liefert dessen
Rückgabewert über retvalp zurück.
Ressourcen automatisch bei Beendigung freigeben:
int pthread_detach(pthread_t thread)
Die mit dem Thread thread verbundenen Systemressourcen werden bei dessen
05t-sync 2018-12-14

Beendigung automatisch freigegeben. Der Rückgabewert der Thread-Funktion


kann nicht abgefragt werden.

© dl,bf GBS (WS 18) 5 Tafelübung 5: Synchronisation | 5.2 Schnittstelle 5–8


Beispiel: Matrix-Vektor-Multiplikation

static double a[100][100], b[100], c[100];

int main(int argc, char *argv[]) {


pthread_t tids[100];
...
for(int i = 0; i < 100; i++)
pthread_create(&tids[i], NULL, mult, (void *) i);

for(int i = 0; i < 100; i++)


pthread_join(tids[i], NULL);
...
}

static void *mult(void *cp) {


int i = (int) cp;
double sum = 0;
for(int j = 0; j < 100; j++)
sum += a[i][j] * b[j];
c[i] = sum;
return NULL;
05t-sync 2018-12-14

Casts zwischen int und Zeiger (bei Parameterübergabe für


pthread\_create()) problematisch – nicht zu Hause nachmachen!

© dl,bf GBS (WS 18) 5 Tafelübung 5: Synchronisation | 5.2 Schnittstelle 5–9


Beispiel: Matrix-Vektor-Multiplikation

static double a[100][100], b[100], c[100];

int main(int argc, char *argv[]) {


pthread_t tids[100]; Für jede Zeile der Matrix einen Thread erzeugen
...
for(int i = 0; i < 100; i++)
pthread_create(&tids[i], NULL, mult, (void *) i);

for(int i = 0; i < 100; i++)


pthread_join(tids[i], NULL);
...
}

static void *mult(void *cp) {


int i = (int) cp;
double sum = 0;
for(int j = 0; j < 100; j++)
sum += a[i][j] * b[j];
c[i] = sum;
return NULL;
05t-sync 2018-12-14

Casts zwischen int und Zeiger (bei Parameterübergabe für


pthread\_create()) problematisch – nicht zu Hause nachmachen!

© dl,bf GBS (WS 18) 5 Tafelübung 5: Synchronisation | 5.2 Schnittstelle 5–9


Beispiel: Matrix-Vektor-Multiplikation

static double a[100][100], b[100], c[100];

int main(int argc, char *argv[]) {


pthread_t tids[100]; Für jede Zeile der Matrix einen Thread erzeugen
...
for(int i = 0; i < 100; i++)
pthread_create(&tids[i], NULL, mult, (void *) i);

for(int i = 0; i < 100; i++)


pthread_join(tids[i], NULL);
...
}

static void *mult(void *cp) {


int i = (int) cp;
double sum = 0;
for(int j = 0; j < 100; j++)
sum += a[i][j] * b[j];
c[i] = sum;
return NULL; Elemente einer Zeile bearbeiten
05t-sync 2018-12-14

Casts zwischen int und Zeiger (bei Parameterübergabe für


pthread\_create()) problematisch – nicht zu Hause nachmachen!

© dl,bf GBS (WS 18) 5 Tafelübung 5: Synchronisation | 5.2 Schnittstelle 5–9


Beispiel: Matrix-Vektor-Multiplikation

static double a[100][100], b[100], c[100];

int main(int argc, char *argv[]) {


pthread_t tids[100]; Für jede Zeile der Matrix einen Thread erzeugen
...
for(int i = 0; i < 100; i++)
pthread_create(&tids[i], NULL, mult, (void *) i);

for(int i = 0; i < 100; i++)


pthread_join(tids[i], NULL);
...
} Alle Threads wieder einsammeln

static void *mult(void *cp) {


int i = (int) cp;
double sum = 0;
for(int j = 0; j < 100; j++)
sum += a[i][j] * b[j];
c[i] = sum;
return NULL; Elemente einer Zeile bearbeiten
05t-sync 2018-12-14

Casts zwischen int und Zeiger (bei Parameterübergabe für


pthread\_create()) problematisch – nicht zu Hause nachmachen!

© dl,bf GBS (WS 18) 5 Tafelübung 5: Synchronisation | 5.2 Schnittstelle 5–9


Parameterübergabe bei pthread_create()

Generischer Ansatz mit Hilfe einer Struktur für die Argumente


struct param {
int index;
};
05t-sync 2018-12-14

© dl,bf GBS (WS 18) 5 Tafelübung 5: Synchronisation | 5.2 Schnittstelle 5–10


Parameterübergabe bei pthread_create()

Generischer Ansatz mit Hilfe einer Struktur für die Argumente


struct param {
int index;
};

Für jeden Thread eine eigene Argumenten-Struktur anlegen


Speicher je nach Situation auf dem Heap oder dem Stack allozieren
int main(int argc, char *argv[]) {
pthread_t tids[100];
struct param args[100];

for(int i = 0; i < 100; i++) {


args[i].index = i;
pthread_create(&tids[i], NULL, mult, &args[i]);
}
for(int i = 0; i < 100; i++)
05t-sync 2018-12-14

pthread_join(tids[i], NULL);
...
}

© dl,bf GBS (WS 18) 5 Tafelübung 5: Synchronisation | 5.2 Schnittstelle 5–10


Parameterübergabe bei pthread_create()

static void* mult(void *arg) {


struct param *par = (struct param *) arg;

double sum = 0;
for(int j = 0; j < 100; j++) {
sum += a[par->index][j] * b[j];
}
c[par->index] = sum;
return NULL;
}

Zugriff auf den threadspezifischen Parametersatz über


(gecasteten) Parameter (void *arg → struct param *par)
05t-sync 2018-12-14

© dl,bf GBS (WS 18) 5 Tafelübung 5: Synchronisation | 5.2 Schnittstelle 5–11


Koordinierung – Motivation

Was macht das Programm? Welches Problem kann auftreten?


static double a[100][100], sum;

int main(int argc, char *argv[]) {


pthread_t tids[100];
struct param args[100];

for(int i = 0; i < 100; i++) {


args[i].index = i;
pthread_create(&tids[i], NULL, sumRow, &args[i]);
}
for(int i = 0; i < 100; i++)
pthread_join(tids[i], NULL);
}

static void *sumRow(void *arg) {


struct param *par = (struct param *) arg;
double localSum = 0;
for(int j = 0; j < 100; j++)
05t-sync 2018-12-14

localSum += a[par->index][j];
sum += localSum;
return NULL;
}

© dl,bf GBS (WS 18) 5 Tafelübung 5: Synchronisation | 5.3 Koordinierung 5–12


Koordinierung – Motivation

Was macht das Programm? Welches Problem kann auftreten?


static double a[100][100], sum;

int main(int argc, char *argv[]) {


pthread_t tids[100];
struct param args[100];

for(int i = 0; i < 100; i++) {


args[i].index = i;
pthread_create(&tids[i], NULL, sumRow, &args[i]);
}
for(int i = 0; i < 100; i++)
pthread_join(tids[i], NULL);
}

static void *sumRow(void *arg) {


struct param *par = (struct param *) arg;
double localSum = 0;
for(int j = 0; j < 100; j++)
05t-sync 2018-12-14

localSum += a[par->index][j];
sum += localSum;
return NULL;
}

© dl,bf GBS (WS 18) 5 Tafelübung 5: Synchronisation | 5.3 Koordinierung 5–12


Koordinierung – Motivation

Was macht das Programm? Welches Problem kann auftreten?


static double a[100][100], sum;

int main(int argc, char *argv[]) {


pthread_t tids[100];
struct param args[100];

for(int i = 0; i < 100; i++) {


args[i].index = i;
pthread_create(&tids[i], NULL, sumRow, &args[i]);
}
for(int i = 0; i < 100; i++)
pthread_join(tids[i], NULL);
}

static void *sumRow(void *arg) {


struct param *par = (struct param *) arg;
double localSum = 0;
for(int j = 0; j < 100; j++)
05t-sync 2018-12-14

localSum += a[par->index][j];
sum += localSum;
return NULL;
} Konkurrierender Zugriff

© dl,bf GBS (WS 18) 5 Tafelübung 5: Synchronisation | 5.3 Koordinierung 5–12


Koordinierung – Motivierung Minimalbeispiel

#include<stdio.h>
#include<pthread.h>

#define ROUNDS 10000

int counter = 0;

static void *increment(void *arg) {


for(int j = 0; j < ROUNDS; j++){

counter++;

}
return NULL;
}

int main(int argc, char *argv[]) {


pthread_t t1, t2;
05t-sync 2018-12-14

pthread_create(&t1, NULL, increment, NULL);


pthread_create(&t2, NULL, increment, NULL);

pthread_join(t1, NULL);
pthread_join(t2, NULL);

printf("ist: %d\nsoll: %d\n", counter, ROUNDS*2);


}
© dl,bf GBS (WS 18) 5 Tafelübung 5: Synchronisation | 5.3 Koordinierung 5–13
Koordinierung – Motivierung Minimalbeispiel – Lösung

#include<stdio.h>
#include<pthread.h>
#include<semaphore.h>
#define ROUNDS 10000
sem_t counter_sem;
int counter = 0;

static void *increment(void *arg) {


for(int j = 0; j < ROUNDS; j++){
sem_wait(&counter_sem);
counter++;
sem_post(&counter_sem);
}
return NULL;
}

int main(int argc, char *argv[]) {


pthread_t t1, t2;
sem_init(&counter_sem, 0, 1);
05t-sync 2018-12-14

pthread_create(&t1, NULL, increment, NULL);


pthread_create(&t2, NULL, increment, NULL);

pthread_join(t1, NULL);
pthread_join(t2, NULL);

printf("ist: %d\nsoll: %d\n", counter, ROUNDS*2);


}
© dl,bf GBS (WS 18) 5 Tafelübung 5: Synchronisation | 5.3 Koordinierung 5–14
Semaphore

Zur Koordinierung von Threads können Semaphore verwendet werden


UNIX stellt zur Koordinierung von Prozessen komplexe
Semaphor-Operationen zur Verfügung
Implementierung durch den Systemkern
komplexe Datenstrukturen, aufwändig zu programmieren
für die Koordinierung von Threads viel zu teuer
Stattdessen Verwendung einer eigenen Semaphorimplementierung mit
atomaren down()- und up()-Operationen
Datenstruktur mit (atomarer) Zählervariable
down() dekrementiert Zähler und blockiert Aufrufer, falls Zähler == 0
up() inkrementiert Zähler und weckt ggf. wartende Threads
05t-sync 2018-12-14

Mehr Details: s. Vorlesung 8-23

© dl,bf GBS (WS 18) 5 Tafelübung 5: Synchronisation | 5.3 Koordinierung 5–15


Gegenseitiger Ausschluss

Spezialfall des zählenden Semaphors: Binärer Semaphor


Initialisierung des Semaphors mit 1

Beispiel: Schreibender Zugriff auf ein gemeinsames Datum

down()
down()
Thread wartet
up()
Thread im
kritischen Abschnitt
up()
Thread 1 Thread 2
05t-sync 2018-12-14

© dl,bf GBS (WS 18) 5 Tafelübung 5: Synchronisation | 5.3 Koordinierung 5–16


Limitierung von Ressourcen

Verwendung eines zählenden Semaphors


Beispiel: Nur zwei aktive Threads gleichzeitig gewünscht
Initialisierung des Semaphors mit 2

down()
down()
down()
Thread wartet
up()
up() Thread im
kritischen Abschnitt
up()
Thread 1 Thread 2 Thread 3
05t-sync 2018-12-14

© dl,bf GBS (WS 18) 5 Tafelübung 5: Synchronisation | 5.3 Koordinierung 5–17


Signalisierung

Benachrichtigung eines anderen Threads über ein Ereignis


Beispiel: Bereitstellen von Zwischenergebnissen

down(s1)
up(s2)
Thread wartet

up(s1)
down(s2)

Thread 1 Thread 2 Thread 3


(Erzeuger) (Erzeuger) (Verbraucher)
05t-sync 2018-12-14

© dl,bf GBS (WS 18) 5 Tafelübung 5: Synchronisation | 5.3 Koordinierung 5–18


POSIX Semaphor

Einbinden
#include<semaphore.h>
Übersetzen mit -pthread
Semaphor erzeugen
sem_init(sem_t *sem, int pshared, unsigned int value)

up/down-Operationen
void sem_wait(sem_t *sem)
void sem_post(sem_t *sem)

Semaphor zerstören
void sem_destroy(sem_t *sem)
05t-sync 2018-12-14

© dl,bf GBS (WS 18) 5 Tafelübung 5: Synchronisation | 5.3 Koordinierung 5–19


Formatierte Eingabe mittels scanf(3)
int scanf(const char *format, ...);
Varianten: fscanf für FILE*, sscanf für char*

Funktionsweise analog zu printf(3) : Angabe eines Formatstrings, gefolgt von


dementsprechenden Variablen
Unterschied: Erwartet Zeiger auf die jeweiligen Speicherbereich!
Rückgabe: Anzahl der eingelesenen Elemente

Beispiel
char str[42];
scanf("%s", str);
05t-sync 2018-12-14

© dl,bf GBS (WS 18) 5 Tafelübung 5: Synchronisation | 5.4 Formatierte Eingabe 5–20
Formatierte Eingabe mittels scanf(3)
int scanf(const char *format, ...);
Varianten: fscanf für FILE*, sscanf für char*

Funktionsweise analog zu printf(3) : Angabe eines Formatstrings, gefolgt von


dementsprechenden Variablen
Unterschied: Erwartet Zeiger auf die jeweiligen Speicherbereich!
Rückgabe: Anzahl der eingelesenen Elemente

Gefahr von Pufferüberläufen


char str[42];
scanf("%s", str); �
05t-sync 2018-12-14

© dl,bf GBS (WS 18) 5 Tafelübung 5: Synchronisation | 5.4 Formatierte Eingabe 5–20
Formatierte Eingabe mittels scanf(3)
int scanf(const char *format, ...);
Varianten: fscanf für FILE*, sscanf für char*

Funktionsweise analog zu printf(3) : Angabe eines Formatstrings, gefolgt von


dementsprechenden Variablen
Unterschied: Erwartet Zeiger auf die jeweiligen Speicherbereich!
Rückgabe: Anzahl der eingelesenen Elemente

Lösung: Begrenzung der Länge via Format-String


char str[42];
scanf("%41s", str); �
05t-sync 2018-12-14

© dl,bf GBS (WS 18) 5 Tafelübung 5: Synchronisation | 5.4 Formatierte Eingabe 5–20
Formatierte Eingabe mittels scanf(3)
int scanf(const char *format, ...);
Varianten: fscanf für FILE*, sscanf für char*

Funktionsweise analog zu printf(3) : Angabe eines Formatstrings, gefolgt von


dementsprechenden Variablen
Unterschied: Erwartet Zeiger auf die jeweiligen Speicherbereich!
Rückgabe: Anzahl der eingelesenen Elemente

Lösung: Begrenzung der Länge via Format-String


char str[42];
scanf("%41s", str); �
05t-sync 2018-12-14

Vorsicht bei Puffergrößen


Maximale Feldbreite ohne \0-Terminierung
→ Feldbreite = Puffergröße - 1 für \%s

© dl,bf GBS (WS 18) 5 Tafelübung 5: Synchronisation | 5.4 Formatierte Eingabe 5–20
Formatierte Eingabe mittels scanf(3) : Beispiel

char str[100];
int i;
float f;

char *input = "Test (42) [13.37]";


int matches = sscanf(input,
"%99s (%d) [%f]", &str[0], &i, &f);
05t-sync 2018-12-14

© dl,bf GBS (WS 18) 5 Tafelübung 5: Synchronisation | 5.4 Formatierte Eingabe 5–21
Formatierte Eingabe mittels scanf(3) : Beispiel

char str[100];
int i;
float f;

char *input = "Test (42) [13.37]";


int matches = sscanf(input,
"%99s (%d) [%f]", &str[0], &i, &f);

“Sichere” Variante scanf_s leider nur Optional in C11


� (und in glibc nicht implementiert)
05t-sync 2018-12-14

© dl,bf GBS (WS 18) 5 Tafelübung 5: Synchronisation | 5.4 Formatierte Eingabe 5–21
Überblick: Tafelübung 5: Synchronisation

5 Tafelübung 5: Synchronisation
5.1 Threads
5.2 Schnittstelle
5.3 Koordinierung
5.4 Formatierte Eingabe
5.5 Aufgabe 5: patric
05-patric 2018-12-05
Allgemeines

Funktionsweise der patric


(Paralleles) Bestimmen der Anzahl der Punkte mit ganzzahligen Koordinaten
auf den Kanten / innerhalb vorgegebener Dreiecke
05-patric 2018-12-05

© dl,bf GBS (WS 18) 5 Tafelübung 5: Synchronisation | 5.5 Aufgabe 5: patric 5–23
Allgemeines

Funktionsweise der patric


(Paralleles) Bestimmen der Anzahl der Punkte mit ganzzahligen Koordinaten
auf den Kanten / innerhalb vorgegebener Dreiecke

Ziele der Aufgabe


Programmieren mit der pthread-Bibliothek
Erkennen von Nebenläufigkeitsproblemen
Einsatz geeigneter Koordinierungsmaßnahmen
05-patric 2018-12-05

© dl,bf GBS (WS 18) 5 Tafelübung 5: Synchronisation | 5.5 Aufgabe 5: patric 5–23
Allgemeines

Funktionsweise der patric


(Paralleles) Bestimmen der Anzahl der Punkte mit ganzzahligen Koordinaten
auf den Kanten / innerhalb vorgegebener Dreiecke

Ziele der Aufgabe


Programmieren mit der pthread-Bibliothek
Erkennen von Nebenläufigkeitsproblemen
Einsatz geeigneter Koordinierungsmaßnahmen

Zur Verwendung der Pthreads-Bibliothek ist die gcc-Option -pthread beim


05-patric 2018-12-05

Übersetzen und Linken notwendig

© dl,bf GBS (WS 18) 5 Tafelübung 5: Synchronisation | 5.5 Aufgabe 5: patric 5–23
patric: Eingabeformat am Beispiel

(1,1) , (2,4) , (7,5)


05-patric 2018-12-05

© dl,bf GBS (WS 18) 5 Tafelübung 5: Synchronisation | 5.5 Aufgabe 5: patric 5–24
patric: Eingabeformat am Beispiel

(1,1) , (2,4) , (7,5)

0 1 2 3 4 5 6 7
05-patric 2018-12-05

© dl,bf GBS (WS 18) 5 Tafelübung 5: Synchronisation | 5.5 Aufgabe 5: patric 5–24
patric: Eingabeformat am Beispiel

(1,1) , (2,4) , (7,5)

3
4 boundary points ( )
2

0 1 2 3 4 5 6 7
05-patric 2018-12-05

© dl,bf GBS (WS 18) 5 Tafelübung 5: Synchronisation | 5.5 Aufgabe 5: patric 5–24
patric: Eingabeformat am Beispiel

(1,1) , (2,4) , (7,5)

3
4 boundary points ( )
2
6 interior points ( )
1

0 1 2 3 4 5 6 7
05-patric 2018-12-05

© dl,bf GBS (WS 18) 5 Tafelübung 5: Synchronisation | 5.5 Aufgabe 5: patric 5–24
patric: Eingabeformat am Beispiel

(1,1) , (2,4) , (7,5)

3
4 boundary points ( )
2
6 interior points ( )
1

0 1 2 3 4 5 6 7
05-patric 2018-12-05

+ Nutzung des vorgegebenen Moduls triangle zum Zählen der Punkte

© dl,bf GBS (WS 18) 5 Tafelübung 5: Synchronisation | 5.5 Aufgabe 5: patric 5–24
triangle-Modul

Enthält die vorgegebene Implementierung von


void countPoints(
struct triangle *tri,
void (*callback)(int boundary, int interior)
);

tri: Dreieck, dessen boundary/interior points gezählt werden


callback:Funktion, die periodisch aufgerufen wird und die Anzahl der
gefundenen Punkte seit dem letzten Aufruf übergebenn bekommt.
05-patric 2018-12-05

© dl,bf GBS (WS 18) 5 Tafelübung 5: Synchronisation | 5.5 Aufgabe 5: patric 5–25
Aufgaben der Threads

Hauptthread

Hauptthread (main()): Einlesen der Eingabedaten, Starten eines


Zählthreads pro Dreieck
05-patric 2018-12-05

© dl,bf GBS (WS 18) 5 Tafelübung 5: Synchronisation | 5.5 Aufgabe 5: patric 5–26
Aufgaben der Threads
Zählthread 0
ieck
Dre

Dreieck
Hauptthread Zählthread 1
Dre
ieck

Zählthread 2

Hauptthread (main()): Einlesen der Eingabedaten, Starten eines


Zählthreads pro Dreieck
Zählthread: Zählen der boundary/interior points
05-patric 2018-12-05

© dl,bf GBS (WS 18) 5 Tafelübung 5: Synchronisation | 5.5 Aufgabe 5: patric 5–26
Aufgaben der Threads
Zählthread 0
Zwi
ieck sch
Dre stan en-
d
Dreieck Zwischen-
Hauptthread Zählthread 1 stand
Ausgabethread
Dre en-
ieck sch
Zwi and
st
Zählthread 2

Hauptthread (main()): Einlesen der Eingabedaten, Starten eines


Zählthreads pro Dreieck
Zählthread: Zählen der boundary/interior points
05-patric 2018-12-05

Ausgabethread: Ausgeben des aktuellen Zwischenstands/des finalen


Ergebnisses

© dl,bf GBS (WS 18) 5 Tafelübung 5: Synchronisation | 5.5 Aufgabe 5: patric 5–26

Das könnte Ihnen auch gefallen