Compare commits

..

2 commits

Author SHA1 Message Date
cbcaff9685 Update README.md 2025-06-03 06:55:25 +00:00
d194d9e18d removed comments 2025-06-03 01:49:23 +02:00
6 changed files with 233 additions and 157 deletions

View file

@ -1,32 +1,43 @@
#pragma once #pragma once
#include <mutex> #include <mutex>
#include <condition_variable>
/**
* 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; // Der gespeicherte Wert int value = 0;
std::mutex mtx; // Schützt Lese/Schreibzugriffe int reader_count = 0;
std::mutex model_mutex;
std::mutex count_mutex;
std::condition_variable no_writer;
public: public:
/**
* Liest den aktuellen Wert
* @return Der gespeicherte Wert
*/
int read() { int read() {
std::lock_guard<std::mutex> lock(mtx); std::unique_lock<std::mutex> count_lock(count_mutex);
return value; 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;
} }
/** void write(int new_value) {
* Schreibt einen neuen Wert std::unique_lock<std::mutex> lock(model_mutex);
* @param new_val Der neue Wert value = new_value;
*/
void write(int new_val) { no_writer.wait(lock, [this]() {
std::lock_guard<std::mutex> lock(mtx); return reader_count == 0;
value = new_val; });
} }
}; };

View file

@ -1,26 +1,75 @@
#include "sensor_network.h" #include "sensor_network.h"
#include <iostream> #include <iostream>
#include <string>
#include <limits>
#include <thread>
/** constexpr size_t DEFAULT_NUM_SENSORS = 3;
* Hauptprogramm constexpr size_t DEFAULT_NUM_ANALYSERS = 2;
* Startet die Simulation mit festen Parametern constexpr int DEFAULT_RUN_TIME = 30;
* (Könnte leicht für interaktive Eingabe erweitert werden) constexpr size_t DEFAULT_BUFFER_SIZE = 8;
*/
int main() { template<size_t N>
// Netzwerk mit Puffergröße 8 erstellen void run_simulation(size_t num_sensors, size_t num_analysers, int run_time) {
SensorNetwork<8> network; SensorNetwork<N> network;
std::cout << "\n=== Simulation gestartet ===\n"
std::cout << "Starting simulation...\n"; << "Sensoren: " << num_sensors << "\n"
<< "Analysemodule: " << num_analysers << "\n"
// 2 Sensoren und 2 Analyse-Module starten << "Puffergröße: " << N << "\n"
network.start(2, 2); << "Laufzeit: " << run_time << "s\n\n";
// 30 Sekunden laufen lassen network.start(num_sensors, num_analysers);
std::this_thread::sleep_for(std::chrono::seconds(30)); std::this_thread::sleep_for(std::chrono::seconds(run_time));
// Netzwerk stoppen
network.stop(); 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<int>(
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<DEFAULT_BUFFER_SIZE>(
num_sensors, num_analysers, run_time
);
}
std::cout << "Simulation erfolgreich abgeschlossen.\n";
return 0; return 0;
} }

View file

@ -1,63 +1,63 @@
#pragma once #pragma once
#include <array> #include <vector>
#include <cstddef>
#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; // Speicher für die Elemente static_assert(N > 1, "Buffer size must be greater than 1");
size_t read = 0; // Lese-Position
size_t write = 0; // Schreib-Position
bool full = false; // Flag für vollen Puffer
std::mutex mtx; // Schützt alle Zugriffe private:
std::condition_variable cv; // Synchronisiert Leser std::vector<int> 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: public:
/** RingBuffer() : data(N, 0) {}
* 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::unique_lock<std::mutex> lock(mtx);
data[write] = value;
write = (write + 1) % N; // Ringverhalten data[write_ptr] = value;
if (full) read = (read + 1) % N; // Überschreiben
full = (write == read); // Update Voll-Flag if(full) {
cv.notify_one(); // Wecke einen Leser 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() { 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; }); not_empty.wait(lock, [this]() {
int val = data[read]; return !is_empty();
read = (read + 1) % N; // Ringverhalten });
full = false; // Nicht mehr voll
return val; 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;
} }
}; };

Binary file not shown.

View file

@ -3,77 +3,92 @@
#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 num_sensors, size_t num_analysers) {
running = true; running = true;
// Sensor-Threads erstellen for(size_t i = 0; i < num_sensors; ++i) {
for (size_t i = 0; i < sensors; ++i) { sensors.emplace_back([this, i] {
threads.emplace_back([this] { sensor_thread(i);
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));
}
}); });
} }
// Analyse-Threads erstellen for(size_t i = 0; i < num_analysers; ++i) {
for (size_t i = 0; i < analysers; ++i) { analysers.emplace_back([this, i] {
threads.emplace_back([this] { analyser_thread(i);
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";
}
}); });
} }
// Controller-Thread erstellen controller = std::thread([this] {
threads.emplace_back([this] { controller_thread();
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);
}
}); });
} }
/**
* 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; // Signal zum Stoppen running = false;
// Auf alle Threads warten for(auto& t : sensors) {
for (auto& t : threads) {
if (t.joinable()) t.join(); if (t.joinable()) t.join();
} }
for(auto& t : analysers) {
if (t.joinable()) t.join();
}
if (controller.joinable()) {
controller.join();
}
}
template <size_t N>
void SensorNetwork<N>::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 <size_t N>
void SensorNetwork<N>::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 <size_t N>
void SensorNetwork<N>::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<8>;
template class SensorNetwork<16>; template class SensorNetwork<16>;
template class SensorNetwork<32>; template class SensorNetwork<32>;

View file

@ -5,25 +5,26 @@
#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; // 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};
std::vector<std::thread> threads; // Alle Threads
std::vector<std::thread> sensors;
std::vector<std::thread> analysers;
std::thread controller;
public: 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(); void stop();
private:
void sensor_thread(int id);
void analyser_thread(int id);
void controller_thread();
}; };