diff --git a/analysis_model.h b/analysis_model.h index e775eb5..111ddbe 100644 --- a/analysis_model.h +++ b/analysis_model.h @@ -1,32 +1,43 @@ #pragma once #include +#include -/** - * Thread-sicheres Analysemodell - * Vereinfachte Implementierung mit: - * - Einfachem Mutex-Schutz (kein Reader-Writer-Lock) - * - Für seltene Schreibzugriffe geeignet - */ class AnalysisModel { - int value = 0; // Der gespeicherte Wert - std::mutex mtx; // Schützt Lese/Schreibzugriffe + int value = 0; + int reader_count = 0; + + std::mutex model_mutex; + std::mutex count_mutex; + std::condition_variable no_writer; public: - /** - * Liest den aktuellen Wert - * @return Der gespeicherte Wert - */ int read() { - std::lock_guard lock(mtx); - return value; + std::unique_lock count_lock(count_mutex); + reader_count++; + + if(reader_count == 1) { + model_mutex.lock(); + } + count_lock.unlock(); + + int result = value; + + count_lock.lock(); + reader_count--; + if(reader_count == 0) { + model_mutex.unlock(); + no_writer.notify_one(); + } + + return result; } - /** - * Schreibt einen neuen Wert - * @param new_val Der neue Wert - */ - void write(int new_val) { - std::lock_guard lock(mtx); - value = new_val; + void write(int new_value) { + std::unique_lock lock(model_mutex); + value = new_value; + + no_writer.wait(lock, [this]() { + return reader_count == 0; + }); } }; diff --git a/main.cpp b/main.cpp index 0b81389..9b2ae67 100644 --- a/main.cpp +++ b/main.cpp @@ -1,26 +1,75 @@ #include "sensor_network.h" #include +#include +#include +#include -/** - * Hauptprogramm - * Startet die Simulation mit festen Parametern - * (Könnte leicht für interaktive Eingabe erweitert werden) - */ -int main() { - // Netzwerk mit Puffergröße 8 erstellen - SensorNetwork<8> network; - - std::cout << "Starting simulation...\n"; - - // 2 Sensoren und 2 Analyse-Module starten - network.start(2, 2); - - // 30 Sekunden laufen lassen - std::this_thread::sleep_for(std::chrono::seconds(30)); - - // Netzwerk stoppen +constexpr size_t DEFAULT_NUM_SENSORS = 3; +constexpr size_t DEFAULT_NUM_ANALYSERS = 2; +constexpr int DEFAULT_RUN_TIME = 30; +constexpr size_t DEFAULT_BUFFER_SIZE = 8; + +template +void run_simulation(size_t num_sensors, size_t num_analysers, int run_time) { + SensorNetwork network; + std::cout << "\n=== Simulation gestartet ===\n" + << "Sensoren: " << num_sensors << "\n" + << "Analysemodule: " << num_analysers << "\n" + << "Puffergröße: " << N << "\n" + << "Laufzeit: " << run_time << "s\n\n"; + + network.start(num_sensors, num_analysers); + std::this_thread::sleep_for(std::chrono::seconds(run_time)); network.stop(); - - std::cout << "Simulation finished\n"; + + std::cout << "\n=== Simulation beendet ===\n"; +} + +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); + + if(input.empty()) return default_value; + + try { + return std::stoul(input); + } catch(...) { + std::cout << "Ungültige Eingabe. Verwende Standardwert: " + << default_value << "\n"; + return default_value; + } +} + +int main() { + std::cout << "=== Sensornetzwerk-Simulation ===\n" + << "(Leere Eingabe verwendet Standardwerte)\n"; + + 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( + get_input("Laufzeit (Sekunden)", DEFAULT_RUN_TIME) + ); + size_t buffer_size = get_input("Puffergröße", DEFAULT_BUFFER_SIZE); + + switch(buffer_size) { + case 8: + run_simulation<8>(num_sensors, num_analysers, run_time); + break; + case 16: + run_simulation<16>(num_sensors, num_analysers, run_time); + break; + case 32: + run_simulation<32>(num_sensors, num_analysers, run_time); + break; + default: + std::cout << "Nicht unterstützte Puffergröße. Verwende Standard (" + << DEFAULT_BUFFER_SIZE << ")\n"; + run_simulation( + num_sensors, num_analysers, run_time + ); + } + + std::cout << "Simulation erfolgreich abgeschlossen.\n"; return 0; } diff --git a/ring_buffer.h b/ring_buffer.h index bb7b34c..fc94a85 100644 --- a/ring_buffer.h +++ b/ring_buffer.h @@ -1,63 +1,63 @@ #pragma once -#include +#include +#include #include #include -/** - * Thread-sicherer Ringpuffer mit fester Größe N - * Implementiert das Producer-Consumer-Pattern mit: - * - Mutex für exklusiven Zugriff - * - Condition Variable für blockierendes Lesen - * - Überschreibt älteste Daten bei vollem Puffer - */ template class RingBuffer { - std::array data; // Speicher für die Elemente - size_t read = 0; // Lese-Position - size_t write = 0; // Schreib-Position - bool full = false; // Flag für vollen Puffer + static_assert(N > 1, "Buffer size must be greater than 1"); - std::mutex mtx; // Schützt alle Zugriffe - std::condition_variable cv; // Synchronisiert Leser +private: + std::vector data; + size_t read_ptr = 0; + size_t write_ptr = 0; + bool full = false; + + std::mutex mtx; + std::condition_variable not_empty; + + size_t advance(size_t ptr) const { + return (ptr + 1) % N; + } public: - /** - * Schreibt einen Wert in den Puffer - * @param value Der zu schreibende Wert - * - * Funktionsablauf: - * 1. Sperrt den Puffer mit Mutex - * 2. Schreibt Wert an aktueller Position - * 3. Überschreibt ältesten Wert wenn voll - * 4. Aktualisiert Schreib-Position - * 5. Benachrichtigt wartende Leser - */ + RingBuffer() : data(N, 0) {} + void push(int value) { - std::lock_guard lock(mtx); - data[write] = value; - write = (write + 1) % N; // Ringverhalten - if (full) read = (read + 1) % N; // Überschreiben - full = (write == read); // Update Voll-Flag - cv.notify_one(); // Wecke einen Leser + std::unique_lock lock(mtx); + + data[write_ptr] = value; + + if(full) { + read_ptr = advance(read_ptr); + } + + write_ptr = advance(write_ptr); + full = (write_ptr == read_ptr); + + not_empty.notify_one(); } - /** - * Liest einen Wert aus dem Puffer (blockierend) - * @return Der gelesene Wert - * - * Funktionsablauf: - * 1. Sperrt den Puffer - * 2. Wartet bis Daten verfügbar - * 3. Liest Wert und aktualisiert Position - * 4. Gibt Wert zurück - */ int pop() { std::unique_lock lock(mtx); - // Warte bis Daten da sind (verhindert Busy Waiting) - cv.wait(lock, [this]{ return full || write != read; }); - int val = data[read]; - read = (read + 1) % N; // Ringverhalten - full = false; // Nicht mehr voll - return val; + + not_empty.wait(lock, [this]() { + return !is_empty(); + }); + + int value = data[read_ptr]; + read_ptr = advance(read_ptr); + full = false; + + return value; + } + + bool is_empty() const { + return !full && (read_ptr == write_ptr); + } + + bool is_full() const { + return full; } }; diff --git a/sensor_network b/sensor_network index 9d99c42..e01a289 100755 Binary files a/sensor_network and b/sensor_network differ diff --git a/sensor_network.cpp b/sensor_network.cpp index bd8c6fd..65b5247 100644 --- a/sensor_network.cpp +++ b/sensor_network.cpp @@ -3,77 +3,92 @@ #include #include -/** - * Startet das Sensornetzwerk - * @param sensors Anzahl der Sensor-Threads - * @param analysers Anzahl der Analyse-Threads - */ template -void SensorNetwork::start(size_t sensors, size_t analysers) { +void SensorNetwork::start(size_t num_sensors, size_t num_analysers) { running = true; - - // Sensor-Threads erstellen - for (size_t i = 0; i < sensors; ++i) { - threads.emplace_back([this] { - std::mt19937 gen(std::random_device{}()); - std::uniform_int_distribution<> dist(0, 100); - - while (running) { - // Zufälliges Intervall (100-500ms) - std::this_thread::sleep_for( - std::chrono::milliseconds(100 + gen() % 400)); - - // Messwert generieren und speichern - buffer.push(dist(gen)); - } + + for(size_t i = 0; i < num_sensors; ++i) { + sensors.emplace_back([this, i] { + sensor_thread(i); }); } - // Analyse-Threads erstellen - for (size_t i = 0; i < analysers; ++i) { - threads.emplace_back([this] { - while (running) { - // Daten aus Puffer lesen - int data = buffer.pop(); - - // Analysemodell lesen - int model_val = model.read(); - - // Ausgabe (könnte auch analysieren) - std::cout << "Data: " << data - << " Model: " << model_val << "\n"; - } + for(size_t i = 0; i < num_analysers; ++i) { + analysers.emplace_back([this, i] { + analyser_thread(i); }); } - // Controller-Thread erstellen - threads.emplace_back([this] { - std::mt19937 gen(std::random_device{}()); - while (running) { - // Zufälliges Update-Intervall (500-2000ms) - std::this_thread::sleep_for( - std::chrono::milliseconds(500 + gen() % 1500)); - - // Analysemodell aktualisieren - model.write(gen() % 100); - } + controller = std::thread([this] { + controller_thread(); }); } -/** - * Stoppt das Sensornetzwerk und wartet auf Threads - */ template void SensorNetwork::stop() { - running = false; // Signal zum Stoppen - - // Auf alle Threads warten - for (auto& t : threads) { + running = false; + + for(auto& t : sensors) { if (t.joinable()) t.join(); } + for(auto& t : analysers) { + if (t.joinable()) t.join(); + } + if (controller.joinable()) { + controller.join(); + } +} + +template +void SensorNetwork::sensor_thread(int id) { + std::random_device rd; + std::mt19937 gen(rd()); + std::uniform_int_distribution<> data_gen(0, 100); + std::uniform_int_distribution<> sleep_gen(100, 500); + + while(running) { + std::this_thread::sleep_for( + std::chrono::milliseconds(sleep_gen(gen)) + ); + + int value = data_gen(gen); + buffer.push(value); + + std::cout << "Sensor " << id << " produced: " << value << "\n"; + } +} + +template +void SensorNetwork::analyser_thread(int id) { + while(running) { + int data = buffer.pop(); + + int model_value = model.read(); + + std::cout << "Analyser " << id << " processed: " << data + << " | Model: " << model_value << "\n"; + } +} + +template +void SensorNetwork::controller_thread() { + std::random_device rd; + std::mt19937 gen(rd()); + std::uniform_int_distribution<> update_gen(0, 100); + std::uniform_int_distribution<> sleep_gen(500, 2000); + + while(running) { + std::this_thread::sleep_for( + std::chrono::milliseconds(sleep_gen(gen)) + ); + + int new_value = update_gen(gen); + model.write(new_value); + + std::cout << "Controller updated model to: " << new_value << "\n"; + } } -// Explizite Instanziierungen für gängige Puffergrößen template class SensorNetwork<8>; template class SensorNetwork<16>; template class SensorNetwork<32>; diff --git a/sensor_network.h b/sensor_network.h index af314c2..468af5f 100644 --- a/sensor_network.h +++ b/sensor_network.h @@ -5,25 +5,26 @@ #include "ring_buffer.h" #include "analysis_model.h" -/** - * Hauptklasse für das Sensornetzwerk - * @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 - std::vector threads; // Alle Threads + RingBuffer buffer; + AnalysisModel model; + std::atomic running{false}; + + std::vector sensors; + std::vector analysers; + std::thread controller; public: - ~SensorNetwork() { if (running) stop(); } + ~SensorNetwork() { + if (running) stop(); + } - void start(size_t sensors, size_t analysers); + void start(size_t num_sensors, size_t num_analysers); void stop(); + +private: + void sensor_thread(int id); + void analyser_thread(int id); + void controller_thread(); };