No description
Find a file
2025-06-03 06:55:25 +00:00
.gitignore Initiales Commit für BS_Praktikum4 Projekt 2025-06-02 22:43:21 +02:00
analysis_model.h removed comments 2025-06-03 01:49:23 +02:00
CMakeLists.txt functional and commented 2025-06-03 00:50:08 +02:00
main.cpp removed comments 2025-06-03 01:49:23 +02:00
README.md Update README.md 2025-06-03 06:55:25 +00:00
ring_buffer.h removed comments 2025-06-03 01:49:23 +02:00
sensor_network removed comments 2025-06-03 01:49:23 +02:00
sensor_network.cpp removed comments 2025-06-03 01:49:23 +02:00
sensor_network.h removed comments 2025-06-03 01:49:23 +02:00

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.
    // 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.
    // 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:

    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:

    // 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!

    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!