« »

Semaphore

In der Vorlesung wurden Threads in C vorgestellt. In dieser Übung gehen wir einen Schritt weiter und nutzen zur Synchronisierung der Threads zusätzlich einen Semaphor. Beachten Sie die Kommentare im Code und nutzen Sie diese als Hilfestellung.

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

sem_t all;
sem_t cereal;

void *addCereal(void *arg) {
    char* word = (char *) arg;
    sem_wait(&cereal); // Warten auf ein Signal von "cereal"
    printf("%s\n", word);
    sem_post(&all); // Erzeugung eines Signals für "all"
    return NULL;
}

void *addPlugins(void *arg){
    char* word = (char *) arg;
    sem_wait(&all); // Warten auf ein Signal von "all"
    printf("%s\n", word); 
    sem_post(&cereal); // Erzeugung eines Signals für "cereal"
    return NULL;
}

int main(int argc, char *argv[]) {
    sem_init(&all, 0, 1); // Erzeugung eines Signals für "all"
    sem_init(&cereal, 0, 0); // Kein Signal wurde für "cereal" erzeugt
    
    pthread_t p1, p2, p3;
    pthread_create(&p1, NULL, addPlugins, "Obst");
    pthread_create(&p2, NULL, addCereal, "Schokolade + Hafer");
    pthread_create(&p3, NULL, addPlugins, "Milch");
    pthread_join(p1, NULL);
    pthread_join(p2, NULL);
    pthread_join(p3, NULL);
    sem_destroy(&all);
    sem_destroy(&cereal);
    return 0;
}

a)

Level 3: Anwenden

Welche I/O-Ausgabe kann das gegebene Programm erzeugen?

Lösung
Milch
Schokolade + Hafer
Obst
Obst
Schokolade + Hafer
Milch

b)

Level 3: Anwenden

Was müssten Sie im Programm ändern, sodass “Schokolade + Hafer” immer als Erstes ausgegeben wird?

Hinweis: Es ist kein Code erforderlich. Sie können z. B. einfach schreiben:
„Z. 100: Erzeugung eines Signals für cereal” oder „Z. 101: Warten auf ein Signal von cereal“.

Lösung
void *addCereal(void *arg) {
    char* word = (char *) arg;
-   sem_wait(&cereal); // Warten auf ein Signal von "cereal"
    printf("%s\n", word);
    sem_post(&all); // Erzeugung eines Signals für "all"
    return NULL;
}
void *addPlugins(void *arg){
    char* word = (char *) arg;
    sem_wait(&all); // Warten auf ein Signal von "all"
    printf("%s\n", word); 
-   sem_post(&cereal); // Erzeugung eines Signals für "cereal"
+   sem_post(&all); // Erzeugung eines Signals für "all"
    return NULL;
}
int main(int argc, char *argv[]) {
-   sem_init(&all, 0, 1); // Erzeugung eines Signals für "all"
+   sem_init(&all, 0, 0); // Keine Signal wurde für "all" erzeugt
-   sem_init(&cereal, 0, 0); // Kein Signal wurde für "cereal" erzeugt
  • Semaphor für cereal ist unnötig
  • entsprechend können alle sem_*(&cereal) entfernt werden
  • zudem: Semaphor all braucht ein zusätzliches Signal, nachdem „Schokolade + Hafer“ ausgegeben wurde

Alternative Lösung:

  • Zeile 25: kein Signal für Semaphor all
  • Zeile 26: Signal für Semaphor cereal
  • Zeile 20: Signal für Semaphor all
  • Zeile 12: Post inzwischen überflüssig

c)

Level 3: Anwenden

Gegeben sind die folgenden drei Methoden, welche von drei unterschiedlichen Threads ausgeführt werden. Mit welchen Werten müssen die Semaphore initialisiert werden, sodass die Buchstaben deterministisch in der richtigen Reihenfolge ausgegeben werden?

#include <pthread.h>
#include <semaphore.h>
#include <stdio.h>
	
sem_t s1;
sem_t s2;
sem_t s3;
sem_t s4;
	
void *t1(void *arg){
    printf("a");
    sem_post(&s1);
	
    sem_wait(&s4);
    printf("e");
}
	
void *t2(void *arg){
    sem_wait(&s1);
    printf("b");
    sem_post(&s2);

    sem_wait(&s3);
    printf("d");
    sem_post(&s4);
}

void *t3(void *arg){
    sem_wait(&s2);
    printf("c");
    sem_post(&s3);
}
Lösung

Alle Semaphore müssen auf 0 initialisiert werden, damit die Ausgabe deterministisch und alphabetisch sortiert ist.

d)

Level 1: Wissen

Zeigen Sie, dass für die gleiche deterministische Ausgabe 3 Semaphore ausreichen, indem Sie die sem_post- und sem_wait-Befehle anpassen.

Vorlage:

#include <semaphore.h>
#include <stdio.h>
	
sem_t s1;
sem_t s2;
sem_t s3;
	
void *t1(void *arg){
    printf("a");
    ?_____________
    
    ?_____________
    printf("e");
}
		
void *t2(void *arg){
    ?_____________
    printf("b");
    ?_____________

    ?_____________
    printf("d");
    ?_____________
}
		
void *t3(void *arg){
    ?_____________
    printf("c");
    ?_____________
}
Lösung
#include <semaphore.h>
#include <stdio.h>
				
sem_t s1;
sem_t s2;
sem_t s3;
				
void *t1(void *arg){
    printf("a");
+   sem_post(&s1);

+   sem_wait(&s2);
    printf("e");
}

void *t2(void *arg){
+   sem_wait(&s1);
    printf("b");
+   sem_post(&s3);

+   sem_wait(&s1);
    printf("d");
+   sem_post(&s2);
}

void *t3(void *arg){
+   sem_wait(&s3);
    printf("c");
+   sem_post(&s1);
}

Lernziele

In dieser Aufgabe …

  • simulieren die Studierenden das Verhalten eines Programms, das auf mehrere Threads aufgeteilt wird.
  • setzen die Studierenden Semaphore ein, um den Programmablauf zu synchronisieren.