added comments

This commit is contained in:
portnoytmy 2025-06-03 01:40:44 +02:00
parent 70aad3fe1c
commit b12ae5b0cb
5 changed files with 120 additions and 27 deletions

View file

@ -1,16 +1,30 @@
#pragma once #pragma once
#include <mutex> #include <mutex>
/**
* Thread-sicheres Analysemodell
* Vereinfachte Implementierung mit:
* - Einfachem Mutex-Schutz (kein Reader-Writer-Lock)
* - Für seltene Schreibzugriffe geeignet
*/
class AnalysisModel { class AnalysisModel {
int value = 0; int value = 0; // Der gespeicherte Wert
std::mutex mtx; std::mutex mtx; // Schützt Lese/Schreibzugriffe
public: public:
/**
* Liest den aktuellen Wert
* @return Der gespeicherte Wert
*/
int read() { int read() {
std::lock_guard<std::mutex> lock(mtx); std::lock_guard<std::mutex> lock(mtx);
return value; return value;
} }
/**
* Schreibt einen neuen Wert
* @param new_val Der neue Wert
*/
void write(int new_val) { void write(int new_val) {
std::lock_guard<std::mutex> lock(mtx); std::lock_guard<std::mutex> lock(mtx);
value = new_val; value = new_val;

View file

@ -1,13 +1,26 @@
#include "sensor_network.h" #include "sensor_network.h"
#include <iostream> #include <iostream>
/**
* Hauptprogramm
* Startet die Simulation mit festen Parametern
* (Könnte leicht für interaktive Eingabe erweitert werden)
*/
int main() { int main() {
// Netzwerk mit Puffergröße 8 erstellen
SensorNetwork<8> network; SensorNetwork<8> network;
std::cout << "Starting simulation...\n";
network.start(2, 2); // 2 sensors, 2 analysers
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)); std::this_thread::sleep_for(std::chrono::seconds(30));
// Netzwerk stoppen
network.stop(); network.stop();
std::cout << "Simulation finished\n"; std::cout << "Simulation finished\n";
return 0; return 0;
} }

View file

@ -3,31 +3,61 @@
#include <mutex> #include <mutex>
#include <condition_variable> #include <condition_variable>
/**
* 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 <size_t N> template <size_t N>
class RingBuffer { class RingBuffer {
std::array<int, N> data; std::array<int, N> data; // Speicher für die Elemente
size_t read = 0; size_t read = 0; // Lese-Position
size_t write = 0; size_t write = 0; // Schreib-Position
bool full = false; bool full = false; // Flag für vollen Puffer
std::mutex mtx;
std::condition_variable cv; std::mutex mtx; // Schützt alle Zugriffe
std::condition_variable cv; // Synchronisiert Leser
public: 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
*/
void push(int value) { void push(int value) {
std::lock_guard<std::mutex> lock(mtx); std::lock_guard<std::mutex> lock(mtx);
data[write] = value; data[write] = value;
write = (write + 1) % N; write = (write + 1) % N; // Ringverhalten
if (full) read = (read + 1) % N; if (full) read = (read + 1) % N; // Überschreiben
full = (write == read); full = (write == read); // Update Voll-Flag
cv.notify_one(); cv.notify_one(); // Wecke einen Leser
} }
/**
* 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() { int pop() {
std::unique_lock<std::mutex> lock(mtx); std::unique_lock<std::mutex> lock(mtx);
// Warte bis Daten da sind (verhindert Busy Waiting)
cv.wait(lock, [this]{ return full || write != read; }); cv.wait(lock, [this]{ return full || write != read; });
int val = data[read]; int val = data[read];
read = (read + 1) % N; read = (read + 1) % N; // Ringverhalten
full = false; full = false; // Nicht mehr voll
return val; return val;
} }
}; };

View file

@ -3,51 +3,77 @@
#include <random> #include <random>
#include <chrono> #include <chrono>
/**
* Startet das Sensornetzwerk
* @param sensors Anzahl der Sensor-Threads
* @param analysers Anzahl der Analyse-Threads
*/
template <size_t N> template <size_t N>
void SensorNetwork<N>::start(size_t sensors, size_t analysers) { void SensorNetwork<N>::start(size_t sensors, size_t analysers) {
running = true; running = true;
// Sensor threads // Sensor-Threads erstellen
for (size_t i = 0; i < sensors; ++i) { for (size_t i = 0; i < sensors; ++i) {
threads.emplace_back([this] { threads.emplace_back([this] {
std::mt19937 gen(std::random_device{}()); std::mt19937 gen(std::random_device{}());
std::uniform_int_distribution<> dist(0, 100); std::uniform_int_distribution<> dist(0, 100);
while (running) { while (running) {
std::this_thread::sleep_for(std::chrono::milliseconds(100 + gen() % 400)); // Zufälliges Intervall (100-500ms)
std::this_thread::sleep_for(
std::chrono::milliseconds(100 + gen() % 400));
// Messwert generieren und speichern
buffer.push(dist(gen)); buffer.push(dist(gen));
} }
}); });
} }
// Analyser threads // Analyse-Threads erstellen
for (size_t i = 0; i < analysers; ++i) { for (size_t i = 0; i < analysers; ++i) {
threads.emplace_back([this] { threads.emplace_back([this] {
while (running) { while (running) {
// Daten aus Puffer lesen
int data = buffer.pop(); int data = buffer.pop();
// Analysemodell lesen
int model_val = model.read(); int model_val = model.read();
std::cout << "Data: " << data << " Model: " << model_val << "\n";
// Ausgabe (könnte auch analysieren)
std::cout << "Data: " << data
<< " Model: " << model_val << "\n";
} }
}); });
} }
// Controller thread // Controller-Thread erstellen
threads.emplace_back([this] { threads.emplace_back([this] {
std::mt19937 gen(std::random_device{}()); std::mt19937 gen(std::random_device{}());
while (running) { while (running) {
std::this_thread::sleep_for(std::chrono::milliseconds(500 + gen() % 1500)); // Zufälliges Update-Intervall (500-2000ms)
std::this_thread::sleep_for(
std::chrono::milliseconds(500 + gen() % 1500));
// Analysemodell aktualisieren
model.write(gen() % 100); model.write(gen() % 100);
} }
}); });
} }
/**
* Stoppt das Sensornetzwerk und wartet auf Threads
*/
template <size_t N> template <size_t N>
void SensorNetwork<N>::stop() { void SensorNetwork<N>::stop() {
running = false; running = false; // Signal zum Stoppen
// Auf alle Threads warten
for (auto& t : threads) { for (auto& t : threads) {
if (t.joinable()) t.join(); if (t.joinable()) t.join();
} }
} }
// Explizite Instanziierungen 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,15 +5,25 @@
#include "ring_buffer.h" #include "ring_buffer.h"
#include "analysis_model.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 <size_t N> template <size_t N>
class SensorNetwork { class SensorNetwork {
RingBuffer<N> buffer; RingBuffer<N> buffer; // Gemeinsamer Datenpuffer
AnalysisModel model; AnalysisModel model; // Geteiltes Analysemodell
std::atomic<bool> running = false; std::atomic<bool> running = false; // Steuerflag für Threads
std::vector<std::thread> threads; std::vector<std::thread> threads; // Alle Threads
public: public:
~SensorNetwork() { if (running) stop(); } ~SensorNetwork() { if (running) stop(); }
void start(size_t sensors, size_t analysers); void start(size_t sensors, size_t analysers);
void stop(); void stop();
}; };