removed comments

This commit is contained in:
portnoytmy 2025-06-03 01:49:23 +02:00
parent e2f3584f47
commit d194d9e18d
6 changed files with 24 additions and 167 deletions

View file

@ -2,50 +2,28 @@
#include <mutex> #include <mutex>
#include <condition_variable> #include <condition_variable>
/**
* Implementiert das Reader-Writer Problem mit:
* - Mehrere gleichzeitige Leser
* - Exklusiver Zugriff für Schreiber
* - Verhindert Writer-Starvation
*/
class AnalysisModel { class AnalysisModel {
int value = 0; // Das geteilte Analysemodell (vereinfacht) int value = 0;
int reader_count = 0; // Zählt aktive Leser int reader_count = 0;
// Synchronisationsprimitive std::mutex model_mutex;
std::mutex model_mutex; // Schützt Schreibzugriffe (exklusiv) std::mutex count_mutex;
std::mutex count_mutex; // Schützt Leserzähler std::condition_variable no_writer;
std::condition_variable no_writer; // Garantiert Fairness
public: 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() { int read() {
std::unique_lock<std::mutex> count_lock(count_mutex); std::unique_lock<std::mutex> count_lock(count_mutex);
reader_count++; reader_count++;
// Erster Leser sperrt für Writer
if(reader_count == 1) { if(reader_count == 1) {
model_mutex.lock(); model_mutex.lock();
} }
count_lock.unlock(); count_lock.unlock();
// Kritischer Abschnitt (Lesen, kann parallel erfolgen)
int result = value; int result = value;
count_lock.lock(); count_lock.lock();
reader_count--; reader_count--;
// Letzter Leser gibt für Writer frei
if(reader_count == 0) { if(reader_count == 0) {
model_mutex.unlock(); model_mutex.unlock();
no_writer.notify_one(); no_writer.notify_one();
@ -54,22 +32,12 @@ public:
return result; 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) { void write(int new_value) {
std::unique_lock<std::mutex> lock(model_mutex); std::unique_lock<std::mutex> lock(model_mutex);
value = new_value; value = new_value;
// Verhindert Writer-Starvation
no_writer.wait(lock, [this]() { no_writer.wait(lock, [this]() {
return reader_count == 0; return reader_count == 0;
}); });
} }
}; };

View file

@ -4,16 +4,11 @@
#include <limits> #include <limits>
#include <thread> #include <thread>
// Standardkonfiguration
constexpr size_t DEFAULT_NUM_SENSORS = 3; constexpr size_t DEFAULT_NUM_SENSORS = 3;
constexpr size_t DEFAULT_NUM_ANALYSERS = 2; 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; constexpr size_t DEFAULT_BUFFER_SIZE = 8;
/**
* Führt die Simulation mit gegebenen Parametern aus
* @tparam N Puffergröße
*/
template<size_t N> template<size_t N>
void run_simulation(size_t num_sensors, size_t num_analysers, int run_time) { void run_simulation(size_t num_sensors, size_t num_analysers, int run_time) {
SensorNetwork<N> network; SensorNetwork<N> 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"; 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) { size_t get_input(const std::string& prompt, size_t default_value) {
std::cout << prompt << " [" << default_value << "]: "; std::cout << prompt << " [" << default_value << "]: ";
std::string input; std::string input;
std::getline(std::cin, input); std::getline(std::cin, input);
// Verwende Standardwert bei leerer Eingabe
if(input.empty()) return default_value; if(input.empty()) return default_value;
// Konvertiere Eingabe
try { try {
return std::stoul(input); return std::stoul(input);
} catch(...) { } catch(...) {
@ -58,7 +45,6 @@ int main() {
std::cout << "=== Sensornetzwerk-Simulation ===\n" std::cout << "=== Sensornetzwerk-Simulation ===\n"
<< "(Leere Eingabe verwendet Standardwerte)\n"; << "(Leere Eingabe verwendet Standardwerte)\n";
// Interaktive Konfiguration
size_t num_sensors = get_input("Anzahl Sensoren", DEFAULT_NUM_SENSORS); size_t num_sensors = get_input("Anzahl Sensoren", DEFAULT_NUM_SENSORS);
size_t num_analysers = get_input("Anzahl Analysemodule", DEFAULT_NUM_ANALYSERS); size_t num_analysers = get_input("Anzahl Analysemodule", DEFAULT_NUM_ANALYSERS);
int run_time = static_cast<int>( int run_time = static_cast<int>(
@ -66,7 +52,6 @@ int main() {
); );
size_t buffer_size = get_input("Puffergröße", DEFAULT_BUFFER_SIZE); size_t buffer_size = get_input("Puffergröße", DEFAULT_BUFFER_SIZE);
// Starte Simulation basierend auf Puffergröße
switch(buffer_size) { switch(buffer_size) {
case 8: case 8:
run_simulation<8>(num_sensors, num_analysers, run_time); run_simulation<8>(num_sensors, num_analysers, run_time);
@ -87,4 +72,4 @@ int main() {
std::cout << "Simulation erfolgreich abgeschlossen.\n"; std::cout << "Simulation erfolgreich abgeschlossen.\n";
return 0; return 0;
} }

View file

@ -4,30 +4,19 @@
#include <mutex> #include <mutex>
#include <condition_variable> #include <condition_variable>
/**
* 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 <size_t N> template <size_t N>
class RingBuffer { class RingBuffer {
static_assert(N > 1, "Buffer size must be greater than 1"); static_assert(N > 1, "Buffer size must be greater than 1");
private: private:
std::vector<int> data; // Speicher für Elemente std::vector<int> data;
size_t read_ptr = 0; // Lesezeiger (nächstes zu lesendes Element) size_t read_ptr = 0;
size_t write_ptr = 0; // Schreibzeiger (nächstes freie Position) size_t write_ptr = 0;
bool full = false; // Flag, ob Puffer voll ist bool full = false;
// Synchronisationsprimitive std::mutex mtx;
std::mutex mtx; // Schützt alle internen Zustände std::condition_variable not_empty;
std::condition_variable not_empty; // Signalisiert, dass Daten verfügbar sind
// Hilfsfunktion: Zeiger mit Ringverhalten bewegen
size_t advance(size_t ptr) const { size_t advance(size_t ptr) const {
return (ptr + 1) % N; return (ptr + 1) % N;
} }
@ -35,56 +24,28 @@ private:
public: public:
RingBuffer() : data(N, 0) {} 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) { void push(int value) {
std::unique_lock<std::mutex> lock(mtx); std::unique_lock<std::mutex> lock(mtx);
// Schreibe Wert
data[write_ptr] = value; data[write_ptr] = value;
// Überschreibe ältesten Wert bei vollem Puffer
if(full) { if(full) {
read_ptr = advance(read_ptr); read_ptr = advance(read_ptr);
} }
// Zeiger aktualisieren
write_ptr = advance(write_ptr); write_ptr = advance(write_ptr);
full = (write_ptr == read_ptr); full = (write_ptr == read_ptr);
// Benachrichtige einen wartenden Consumer
not_empty.notify_one(); 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() { int pop() {
std::unique_lock<std::mutex> lock(mtx); std::unique_lock<std::mutex> lock(mtx);
// Warte bis Daten verfügbar (verhindert Busy Waiting)
not_empty.wait(lock, [this]() { not_empty.wait(lock, [this]() {
return !is_empty(); return !is_empty();
}); });
// Lese und aktualisiere Zustand
int value = data[read_ptr]; int value = data[read_ptr];
read_ptr = advance(read_ptr); read_ptr = advance(read_ptr);
full = false; full = false;
@ -92,13 +53,11 @@ public:
return value; return value;
} }
// Prüft ob Puffer leer ist
bool is_empty() const { bool is_empty() const {
return !full && (read_ptr == write_ptr); return !full && (read_ptr == write_ptr);
} }
// Prüft ob Puffer voll ist
bool is_full() const { bool is_full() const {
return full; return full;
} }
}; };

Binary file not shown.

View file

@ -3,43 +3,31 @@
#include <random> #include <random>
#include <chrono> #include <chrono>
/**
* Startet alle Threads des Netzwerks
* @param num_sensors Anzahl der Sensor-Threads
* @param num_analysers Anzahl der Analyse-Threads
*/
template <size_t N> template <size_t N>
void SensorNetwork<N>::start(size_t num_sensors, size_t num_analysers) { void SensorNetwork<N>::start(size_t num_sensors, size_t num_analysers) {
running = true; running = true;
// Starte Sensor-Threads
for(size_t i = 0; i < num_sensors; ++i) { for(size_t i = 0; i < num_sensors; ++i) {
sensors.emplace_back([this, i] { sensors.emplace_back([this, i] {
sensor_thread(i); sensor_thread(i);
}); });
} }
// Starte Analyse-Threads
for(size_t i = 0; i < num_analysers; ++i) { for(size_t i = 0; i < num_analysers; ++i) {
analysers.emplace_back([this, i] { analysers.emplace_back([this, i] {
analyser_thread(i); analyser_thread(i);
}); });
} }
// Starte Controller-Thread
controller = std::thread([this] { controller = std::thread([this] {
controller_thread(); controller_thread();
}); });
} }
/**
* Stoppt alle Threads und wartet auf Beendigung
*/
template <size_t N> template <size_t N>
void SensorNetwork<N>::stop() { void SensorNetwork<N>::stop() {
running = false; running = false;
// Warte auf Thread-Ende
for(auto& t : sensors) { for(auto& t : sensors) {
if (t.joinable()) t.join(); if (t.joinable()) t.join();
} }
@ -51,29 +39,18 @@ void SensorNetwork<N>::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 <size_t N> template <size_t N>
void SensorNetwork<N>::sensor_thread(int id) { void SensorNetwork<N>::sensor_thread(int id) {
std::random_device rd; std::random_device rd;
std::mt19937 gen(rd()); std::mt19937 gen(rd());
std::uniform_int_distribution<> data_gen(0, 100); // Messwerte 0-100 std::uniform_int_distribution<> data_gen(0, 100);
std::uniform_int_distribution<> sleep_gen(100, 500); // Intervall 100-500ms std::uniform_int_distribution<> sleep_gen(100, 500);
while(running) { while(running) {
// Simuliere Messintervall
std::this_thread::sleep_for( std::this_thread::sleep_for(
std::chrono::milliseconds(sleep_gen(gen)) std::chrono::milliseconds(sleep_gen(gen))
); );
// Generiere und schreibe Messwert
int value = data_gen(gen); int value = data_gen(gen);
buffer.push(value); buffer.push(value);
@ -81,22 +58,11 @@ void SensorNetwork<N>::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 <size_t N> template <size_t N>
void SensorNetwork<N>::analyser_thread(int id) { void SensorNetwork<N>::analyser_thread(int id) {
while(running) { while(running) {
// Blockierendes Lesen aus Puffer
int data = buffer.pop(); int data = buffer.pop();
// Lesender Zugriff auf Analysemodell
int model_value = model.read(); int model_value = model.read();
std::cout << "Analyser " << id << " processed: " << data std::cout << "Analyser " << id << " processed: " << data
@ -104,27 +70,18 @@ void SensorNetwork<N>::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 <size_t N> template <size_t N>
void SensorNetwork<N>::controller_thread() { void SensorNetwork<N>::controller_thread() {
std::random_device rd; std::random_device rd;
std::mt19937 gen(rd()); std::mt19937 gen(rd());
std::uniform_int_distribution<> update_gen(0, 100); // Modellwerte std::uniform_int_distribution<> update_gen(0, 100);
std::uniform_int_distribution<> sleep_gen(500, 2000); // Update-Intervall std::uniform_int_distribution<> sleep_gen(500, 2000);
while(running) { while(running) {
// Warte bis zum nächsten Update
std::this_thread::sleep_for( std::this_thread::sleep_for(
std::chrono::milliseconds(sleep_gen(gen)) std::chrono::milliseconds(sleep_gen(gen))
); );
// Aktualisiere Analysemodell
int new_value = update_gen(gen); int new_value = update_gen(gen);
model.write(new_value); model.write(new_value);
@ -132,7 +89,6 @@ void SensorNetwork<N>::controller_thread() {
} }
} }
// Explizite Instanziierung für gängige Puffergrößen
template class SensorNetwork<8>; template class SensorNetwork<8>;
template class SensorNetwork<16>; template class SensorNetwork<16>;
template class SensorNetwork<32>; template class SensorNetwork<32>;

View file

@ -5,22 +5,12 @@
#include "ring_buffer.h" #include "ring_buffer.h"
#include "analysis_model.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 <size_t N> template <size_t N>
class SensorNetwork { class SensorNetwork {
RingBuffer<N> buffer; // Gemeinsamer Datenpuffer RingBuffer<N> buffer;
AnalysisModel model; // Geteiltes Analysemodell AnalysisModel model;
std::atomic<bool> running{false}; // Steuerflag für Threads std::atomic<bool> running{false};
// Thread-Container
std::vector<std::thread> sensors; std::vector<std::thread> sensors;
std::vector<std::thread> analysers; std::vector<std::thread> analysers;
std::thread controller; std::thread controller;
@ -34,8 +24,7 @@ public:
void stop(); void stop();
private: private:
// Thread-Funktionen
void sensor_thread(int id); void sensor_thread(int id);
void analyser_thread(int id); void analyser_thread(int id);
void controller_thread(); void controller_thread();
}; };