BS_Praktikum4/README.md
2025-06-03 06:55:25 +00:00

154 lines
No EOL
6.4 KiB
Markdown

### Erklärung der Praktikumsaufgabe (Synchronisation)
#### **Kernziel der Aufgabe**
Sie sollen ein **multithreaded Sensornetzwerk** simulieren, das drei Komponenten umfasst:
1. **Sensoren (Producer)**
- Erzeugen regelmäßig Messdaten (z.B. Temperatur) als Zufallszahlen.
- Speichern Daten in einem **gemeinsamen Ringpuffer** (Thread-sicher synchronisiert).
2. **Analyse-Module (Consumer & Reader)**
- Entnehmen Daten aus dem Ringpuffer.
- Lesen **gleichzeitig** ein zentrales Analysemodell (z.B. Kalibrierungsdaten).
3. **System-Controller (Writer)**
- Aktualisiert das Analysemodell in zufälligen Abständen.
#### **Technische Anforderungen**
1. **Synchronisationsmechanismen**
- Nutzen Sie **nur Semaphore und Mutex** (wie in der Vorlesung behandelt).
- Vermeiden Sie **Race Conditions** und **Deadlocks**.
2. **Ringpuffer**
- Vorgegebene Implementierung (nicht threadsicher!) → Sie müssen **Zugriff synchronisieren**.
- Eigenschaften:
- Größe `BUFFER_SIZE` (z.B. 8 Elemente).
- Überschreibt älteste Daten bei Vollschreiben (`ring_push`).
- Blockiert beim Lesen, wenn leer (`ring_pop`).
3. **Analysemodell**
- Einfache Implementierung als **globaler Integer** (keine komplexe Analyse).
- **Reader-Writer-Problem**:
- Mehrere Leser (Analyse-Module) dürfen **gleichzeitig** lesen.
- Writer (Controller) benötigt **exklusiven Zugriff** (kein Leser/Writer aktiv).
- **Starvation des Writers verhindern** (Controller darf nicht endlos warten).
4. **Simulation**
- Sensoren/Controller: `sleep()` + `rand()` für Intervalle.
- Ausgaben: Nutzen Sie `printf()` zur Beobachtung des Systems.
---
### **Zu implementierende Synchronisation**
#### 1. **Ringpuffer (Producer-Consumer Pattern)**
- **Problem**: Paralleler Zugriff von Sensoren (Produzenten) und Analyse-Modulen (Konsumenten).
- **Lösung**:
- **Mutex**: Schützt den Puffer bei `push`/`pop` (strukturelle Integrität).
- **Semaphore `items`**: Zählt belegte Pufferplätze.
- Initialwert: `0` (leer).
- **Producer** (Sensor): Erhöht `items` **nur wenn Puffer vorher nicht voll war** (sonst Überschreiben ohne Signal).
- **Consumer** (Analyse-Modul): Wartet auf `items > 0` vor dem Lesen.
```c
// Pseudocode: Sensor (Producer)
pthread_mutex_lock(&buffer_mutex);
bool was_full = ring_is_full(&rb);
ring_push(&rb, new_data);
if (!was_full) sem_post(&items); // Signal an Consumer
pthread_mutex_unlock(&buffer_mutex);
// Pseudocode: Analyse-Modul (Consumer)
sem_wait(&items); // Wartet auf Daten
pthread_mutex_lock(&buffer_mutex);
ring_pop(&rb, &data);
pthread_mutex_unlock(&buffer_mutex);
```
#### 2. **Analysemodell (Reader-Writer Problem mit Fairness)**
- **Problem**: Paralleles Lesen vs. exklusives Schreiben + Verhinderung von Writer-Starvation.
- **Lösung** (Fairness mit "Turnstile"-Semaphor):
- **Semaphore `turn`**: Garantiert FIFO-Reihenfolge (Fairness).
- **Semaphore `rw_mutex`**: Schützt exklusive Schreibzugriffe.
- **Mutex `read_mutex`**: Schützt Leser-Zähler (`read_count`).
- **Integer `read_count`**: Zählt aktive Leser.
```c
// Pseudocode: Analyse-Modul (Reader)
sem_wait(&turn); // Stelle dich in Warteschlange
sem_post(&turn); // Weiterleitung (sofort)
pthread_mutex_lock(&read_mutex);
read_count++;
if (read_count == 1) sem_wait(&rw_mutex); // Erster Leser sperrt Writer
pthread_mutex_unlock(&read_mutex);
// LESEZUGRIFF auf shared_model
pthread_mutex_lock(&read_mutex);
read_count--;
if (read_count == 0) sem_post(&rw_mutex); // Letzter Leser erlaubt Writer
pthread_mutex_unlock(&read_mutex);
// Pseudocode: Controller (Writer)
sem_wait(&turn); // Warte auf deine Reihenfolge
sem_wait(&rw_mutex); // Fordere exklusiven Zugriff an
sem_post(&turn); // Freigabe für Nächsten in Warteschlange
// SCHREIBZUGRIFF auf shared_model
sem_post(&rw_mutex); // Freigabe
```
---
### **Test und Reflexion**
Starten Sie das System mit verschiedenen Parametern und beobachten Sie:
1. **Durchsatzrate**
- Wie viele Daten werden pro Zeiteinheit verarbeitet?
- Variieren Sie: Puffergröße, Anzahl der Sensoren/Analyse-Module.
2. **Starvation/Deadlocks**
- Tritt Starvation auf (z.B. Controller wird blockiert)?
- Verursachen bestimmte Konfigurationen Deadlocks?
3. **Lastszenarien**
- **Viele Sensoren**: Läuft der Puffer über? (Datenverlust durch Überschreiben)
- **Viele Leser**: Wird der Controller blockiert? Wie wirkt sich Fairness aus?
4. **Systemunterbrechungen**
- Simulieren Sie OTA-Updates: Controller führt `sleep()` während Schreibzugriff aus → Blockiert Leser?
5. **Optimale Parameter**
- Finden Sie Konfigurationen, bei denen das System besonders effizient ist.
---
### **Umsetzungshinweise**
- **Globale Variablen**:
```c
RingBuffer rb; // Ringpuffer
int shared_model = 0; // Analysemodell (Integer)
sem_t items, rw_mutex, turn; // Semaphore
pthread_mutex_t buffer_mutex, read_mutex; // Mutexe
int read_count = 0; // Zähler aktiver Leser
```
- **Thread-Erstellung**:
```c
// Beispiel: Starte 2 Sensoren, 3 Analyse-Module, 1 Controller
pthread_t sensor_threads[2], analyser_threads[3], controller_thread;
for (int i = 0; i < 2; i++) pthread_create(&sensor_threads[i], NULL, sensor_func, NULL);
for (int i = 0; i < 3; i++) pthread_create(&analyser_threads[i], NULL, analyser_func, NULL);
pthread_create(&controller_thread, NULL, controller_func, NULL);
```
- **Wichtig**: Initialisieren Sie alle Synchronisationsmittel vor Thread-Start!
```c
sem_init(&items, 0, 0); // Initialwert 0
sem_init(&rw_mutex, 0, 1); // Initialwert 1 (frei)
sem_init(&turn, 0, 1); // Initialwert 1 (FIFO-Reihenfolge)
pthread_mutex_init(&buffer_mutex, NULL);
pthread_mutex_init(&read_mutex, NULL);
```
---
### **Warum diese Lösung?**
- **Ringpuffer**: Produzenten überschreiben alte Daten, Konsumenten warten bei Leerpuffer → Effizient & verlusttolerant.
- **Analysemodell**:
- `turn`-Semaphor verhindert Writer-Starvation (Fairness).
- Leser können parallel arbeiten, solange kein Writer aktiv ist.
- **Synchronisationsmittel**: Beschränkt auf Semaphore/Mutex (vorgabekonform).
Mit dieser Struktur erfüllen Sie alle Lernziele:
✅ Reader-Writer-Problem
✅ Producer-Consumer-Pattern
✅ Vermeidung von Race Conditions & Deadlocks!