diff --git a/analysis_model.h b/analysis_model.h index 4b4be10..111ddbe 100644 --- a/analysis_model.h +++ b/analysis_model.h @@ -2,50 +2,28 @@ #include #include -/** - * Implementiert das Reader-Writer Problem mit: - * - Mehrere gleichzeitige Leser - * - Exklusiver Zugriff für Schreiber - * - Verhindert Writer-Starvation - */ class AnalysisModel { - int value = 0; // Das geteilte Analysemodell (vereinfacht) - int reader_count = 0; // Zählt aktive Leser + int value = 0; + int reader_count = 0; - // Synchronisationsprimitive - std::mutex model_mutex; // Schützt Schreibzugriffe (exklusiv) - std::mutex count_mutex; // Schützt Leserzähler - std::condition_variable no_writer; // Garantiert Fairness + std::mutex model_mutex; + std::mutex count_mutex; + std::condition_variable no_writer; public: - /** - * Lesender Zugriff - * @return Aktueller Wert des Modells - * - * Funktionsweise: - * 1. Sperrt count_mutex und inkrementiert reader_count - * 2. Erster Leser sperrt model_mutex (blockiert Writer) - * 3. Entsperrt count_mutex während des Lesens - * 4. Liest Wert - * 5. Sperrt count_mutex zum Dekrementieren - * 6. Letzter Leser entsperrt model_mutex und benachrichtigt Writer - */ int read() { std::unique_lock count_lock(count_mutex); reader_count++; - // Erster Leser sperrt für Writer if(reader_count == 1) { model_mutex.lock(); } count_lock.unlock(); - // Kritischer Abschnitt (Lesen, kann parallel erfolgen) int result = value; count_lock.lock(); reader_count--; - // Letzter Leser gibt für Writer frei if(reader_count == 0) { model_mutex.unlock(); no_writer.notify_one(); @@ -54,22 +32,12 @@ public: return result; } - /** - * Schreibender Zugriff - * @param new_value Neuer Wert für das Modell - * - * Funktionsweise: - * 1. Sperrt model_mutex (exklusiver Zugriff) - * 2. Schreibt neuen Wert - * 3. Wartet bis alle Leser fertig sind (Starvation Prevention) - */ void write(int new_value) { std::unique_lock lock(model_mutex); value = new_value; - // Verhindert Writer-Starvation no_writer.wait(lock, [this]() { return reader_count == 0; }); } -}; \ No newline at end of file +}; diff --git a/main.cpp b/main.cpp index b608ad5..9b2ae67 100644 --- a/main.cpp +++ b/main.cpp @@ -4,16 +4,11 @@ #include #include -// Standardkonfiguration constexpr size_t DEFAULT_NUM_SENSORS = 3; constexpr size_t DEFAULT_NUM_ANALYSERS = 2; -constexpr int DEFAULT_RUN_TIME = 30; // Sekunden +constexpr int DEFAULT_RUN_TIME = 30; constexpr size_t DEFAULT_BUFFER_SIZE = 8; -/** - * Führt die Simulation mit gegebenen Parametern aus - * @tparam N Puffergröße - */ template void run_simulation(size_t num_sensors, size_t num_analysers, int run_time) { SensorNetwork network; @@ -30,21 +25,13 @@ void run_simulation(size_t num_sensors, size_t num_analysers, int run_time) { std::cout << "\n=== Simulation beendet ===\n"; } -/** - * Liest Benutzereingabe mit Standardwert - * @param prompt Eingabeaufforderung - * @param default_value Standardwert bei leerer Eingabe - * @return Eingegebener oder Standardwert - */ size_t get_input(const std::string& prompt, size_t default_value) { std::cout << prompt << " [" << default_value << "]: "; std::string input; std::getline(std::cin, input); - // Verwende Standardwert bei leerer Eingabe if(input.empty()) return default_value; - // Konvertiere Eingabe try { return std::stoul(input); } catch(...) { @@ -58,7 +45,6 @@ int main() { std::cout << "=== Sensornetzwerk-Simulation ===\n" << "(Leere Eingabe verwendet Standardwerte)\n"; - // Interaktive Konfiguration size_t num_sensors = get_input("Anzahl Sensoren", DEFAULT_NUM_SENSORS); size_t num_analysers = get_input("Anzahl Analysemodule", DEFAULT_NUM_ANALYSERS); int run_time = static_cast( @@ -66,7 +52,6 @@ int main() { ); size_t buffer_size = get_input("Puffergröße", DEFAULT_BUFFER_SIZE); - // Starte Simulation basierend auf Puffergröße switch(buffer_size) { case 8: run_simulation<8>(num_sensors, num_analysers, run_time); @@ -87,4 +72,4 @@ int main() { std::cout << "Simulation erfolgreich abgeschlossen.\n"; return 0; -} \ No newline at end of file +} diff --git a/ring_buffer.h b/ring_buffer.h index ee992c8..fc94a85 100644 --- a/ring_buffer.h +++ b/ring_buffer.h @@ -4,30 +4,19 @@ #include #include -/** - * Thread-sicherer Ringpuffer mit fester Größe - * @tparam N Größe des Puffers (muss > 1 sein) - * - * Implementiert das Producer-Consumer Pattern mit: - * - Mutex für exklusiven Zugriff - * - Condition Variable für blockierendes Pop - * - Überschreibt älteste Daten bei vollem Puffer - */ template class RingBuffer { static_assert(N > 1, "Buffer size must be greater than 1"); private: - std::vector data; // Speicher für Elemente - size_t read_ptr = 0; // Lesezeiger (nächstes zu lesendes Element) - size_t write_ptr = 0; // Schreibzeiger (nächstes freie Position) - bool full = false; // Flag, ob Puffer voll ist + std::vector data; + size_t read_ptr = 0; + size_t write_ptr = 0; + bool full = false; - // Synchronisationsprimitive - std::mutex mtx; // Schützt alle internen Zustände - std::condition_variable not_empty; // Signalisiert, dass Daten verfügbar sind + std::mutex mtx; + std::condition_variable not_empty; - // Hilfsfunktion: Zeiger mit Ringverhalten bewegen size_t advance(size_t ptr) const { return (ptr + 1) % N; } @@ -35,56 +24,28 @@ private: public: RingBuffer() : data(N, 0) {} - /** - * Schreibt Wert in den Puffer - * @param value Der zu schreibende Wert - * - * Funktionsweise: - * 1. Sperrt Mutex für exklusiven Zugriff - * 2. Schreibt Wert an aktueller write_ptr - * 3. Bei vollem Puffer: Bewegt read_ptr (überschreibt ältesten Wert) - * 4. Aktualisiert write_ptr und full-Flag - * 5. Benachrichtigt einen wartenden Consumer - */ void push(int value) { std::unique_lock lock(mtx); - // Schreibe Wert data[write_ptr] = value; - // Überschreibe ältesten Wert bei vollem Puffer if(full) { read_ptr = advance(read_ptr); } - // Zeiger aktualisieren write_ptr = advance(write_ptr); full = (write_ptr == read_ptr); - // Benachrichtige einen wartenden Consumer not_empty.notify_one(); } - /** - * Liest Wert aus dem Puffer (blockierend) - * @return Der gelesene Wert - * - * Funktionsweise: - * 1. Sperrt Mutex - * 2. Wartet mit Condition Variable bis Daten verfügbar - * 3. Liest Wert an read_ptr - * 4. Aktualisiert read_ptr und full-Flag - * 5. Gibt Wert zurück - */ int pop() { std::unique_lock lock(mtx); - // Warte bis Daten verfügbar (verhindert Busy Waiting) not_empty.wait(lock, [this]() { return !is_empty(); }); - // Lese und aktualisiere Zustand int value = data[read_ptr]; read_ptr = advance(read_ptr); full = false; @@ -92,13 +53,11 @@ public: return value; } - // Prüft ob Puffer leer ist bool is_empty() const { return !full && (read_ptr == write_ptr); } - // Prüft ob Puffer voll ist bool is_full() const { return full; } -}; \ No newline at end of file +}; diff --git a/sensor_network b/sensor_network index a918fbc..e01a289 100755 Binary files a/sensor_network and b/sensor_network differ diff --git a/sensor_network.cpp b/sensor_network.cpp index 038a7ca..65b5247 100644 --- a/sensor_network.cpp +++ b/sensor_network.cpp @@ -3,43 +3,31 @@ #include #include -/** - * Startet alle Threads des Netzwerks - * @param num_sensors Anzahl der Sensor-Threads - * @param num_analysers Anzahl der Analyse-Threads - */ template void SensorNetwork::start(size_t num_sensors, size_t num_analysers) { running = true; - // Starte Sensor-Threads for(size_t i = 0; i < num_sensors; ++i) { sensors.emplace_back([this, i] { sensor_thread(i); }); } - // Starte Analyse-Threads for(size_t i = 0; i < num_analysers; ++i) { analysers.emplace_back([this, i] { analyser_thread(i); }); } - // Starte Controller-Thread controller = std::thread([this] { controller_thread(); }); } -/** - * Stoppt alle Threads und wartet auf Beendigung - */ template void SensorNetwork::stop() { running = false; - // Warte auf Thread-Ende for(auto& t : sensors) { if (t.joinable()) t.join(); } @@ -51,29 +39,18 @@ void SensorNetwork::stop() { } } -/** - * Thread-Funktion für Sensoren (Producer) - * @param id Eindeutige ID des Sensors - * - * Funktionsweise: - * 1. Generiert zufällige Messwerte - * 2. Wartet zufällige Zeit (Messintervall) - * 3. Schreibt Daten in Ringpuffer - */ template void SensorNetwork::sensor_thread(int id) { std::random_device rd; std::mt19937 gen(rd()); - std::uniform_int_distribution<> data_gen(0, 100); // Messwerte 0-100 - std::uniform_int_distribution<> sleep_gen(100, 500); // Intervall 100-500ms + std::uniform_int_distribution<> data_gen(0, 100); + std::uniform_int_distribution<> sleep_gen(100, 500); while(running) { - // Simuliere Messintervall std::this_thread::sleep_for( std::chrono::milliseconds(sleep_gen(gen)) ); - // Generiere und schreibe Messwert int value = data_gen(gen); buffer.push(value); @@ -81,22 +58,11 @@ void SensorNetwork::sensor_thread(int id) { } } -/** - * Thread-Funktion für Analyse-Module (Consumer) - * @param id Eindeutige ID des Moduls - * - * Funktionsweise: - * 1. Liest Daten aus Ringpuffer (blockierend) - * 2. Liest aktuelles Analysemodell - * 3. Verarbeitet Daten (hier nur Ausgabe) - */ template void SensorNetwork::analyser_thread(int id) { while(running) { - // Blockierendes Lesen aus Puffer int data = buffer.pop(); - // Lesender Zugriff auf Analysemodell int model_value = model.read(); std::cout << "Analyser " << id << " processed: " << data @@ -104,27 +70,18 @@ void SensorNetwork::analyser_thread(int id) { } } -/** - * Thread-Funktion für System-Controller (Writer) - * - * Funktionsweise: - * 1. Wartet zufällige Zeit zwischen Updates - * 2. Schreibt neuen Wert ins Analysemodell - */ template void SensorNetwork::controller_thread() { std::random_device rd; std::mt19937 gen(rd()); - std::uniform_int_distribution<> update_gen(0, 100); // Modellwerte - std::uniform_int_distribution<> sleep_gen(500, 2000); // Update-Intervall + std::uniform_int_distribution<> update_gen(0, 100); + std::uniform_int_distribution<> sleep_gen(500, 2000); while(running) { - // Warte bis zum nächsten Update std::this_thread::sleep_for( std::chrono::milliseconds(sleep_gen(gen)) ); - // Aktualisiere Analysemodell int new_value = update_gen(gen); model.write(new_value); @@ -132,7 +89,6 @@ void SensorNetwork::controller_thread() { } } -// Explizite Instanziierung für gängige Puffergrößen template class SensorNetwork<8>; template class SensorNetwork<16>; -template class SensorNetwork<32>; \ No newline at end of file +template class SensorNetwork<32>; diff --git a/sensor_network.h b/sensor_network.h index 1480dc3..468af5f 100644 --- a/sensor_network.h +++ b/sensor_network.h @@ -5,22 +5,12 @@ #include "ring_buffer.h" #include "analysis_model.h" -/** - * Hauptklasse des Sensornetzwerks - * @tparam N Größe des Ringpuffers - * - * Verwaltet alle Komponenten: - * - Ringpuffer für Sensordaten - * - Analysemodell - * - Threads für Sensoren, Analyse und Controller - */ template class SensorNetwork { - RingBuffer buffer; // Gemeinsamer Datenpuffer - AnalysisModel model; // Geteiltes Analysemodell - std::atomic running{false}; // Steuerflag für Threads + RingBuffer buffer; + AnalysisModel model; + std::atomic running{false}; - // Thread-Container std::vector sensors; std::vector analysers; std::thread controller; @@ -34,8 +24,7 @@ public: void stop(); private: - // Thread-Funktionen void sensor_thread(int id); void analyser_thread(int id); void controller_thread(); -}; \ No newline at end of file +};