Compare commits
1 commit
master
...
complicate
| Author | SHA1 | Date | |
|---|---|---|---|
| f3a82ab88b |
7 changed files with 170 additions and 26 deletions
|
|
@ -1,4 +1,4 @@
|
||||||
### Erklärung der Praktikumsaufgabe (Synchronisation)
|
/* ### Erklärung der Praktikumsaufgabe (Synchronisation)
|
||||||
|
|
||||||
#### **Kernziel der Aufgabe**
|
#### **Kernziel der Aufgabe**
|
||||||
Sie sollen ein **multithreaded Sensornetzwerk** simulieren, das drei Komponenten umfasst:
|
Sie sollen ein **multithreaded Sensornetzwerk** simulieren, das drei Komponenten umfasst:
|
||||||
|
|
@ -151,4 +151,5 @@ Starten Sie das System mit verschiedenen Parametern und beobachten Sie:
|
||||||
Mit dieser Struktur erfüllen Sie alle Lernziele:
|
Mit dieser Struktur erfüllen Sie alle Lernziele:
|
||||||
✅ Reader-Writer-Problem
|
✅ Reader-Writer-Problem
|
||||||
✅ Producer-Consumer-Pattern
|
✅ Producer-Consumer-Pattern
|
||||||
✅ Vermeidung von Race Conditions & Deadlocks!
|
✅ Vermeidung von Race Conditions & Deadlocks!
|
||||||
|
*/
|
||||||
|
|
@ -2,28 +2,50 @@
|
||||||
#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;
|
int value = 0; // Das geteilte Analysemodell (vereinfacht)
|
||||||
int reader_count = 0;
|
int reader_count = 0; // Zählt aktive Leser
|
||||||
|
|
||||||
std::mutex model_mutex;
|
// Synchronisationsprimitive
|
||||||
std::mutex count_mutex;
|
std::mutex model_mutex; // Schützt Schreibzugriffe (exklusiv)
|
||||||
std::condition_variable no_writer;
|
std::mutex count_mutex; // Schützt Leserzähler
|
||||||
|
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();
|
||||||
|
|
@ -32,12 +54,22 @@ 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;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
19
main.cpp
19
main.cpp
|
|
@ -4,11 +4,16 @@
|
||||||
#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;
|
constexpr int DEFAULT_RUN_TIME = 30; // Sekunden
|
||||||
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;
|
||||||
|
|
@ -25,13 +30,21 @@ 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(...) {
|
||||||
|
|
@ -45,6 +58,7 @@ 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>(
|
||||||
|
|
@ -52,6 +66,7 @@ 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);
|
||||||
|
|
@ -72,4 +87,4 @@ int main() {
|
||||||
|
|
||||||
std::cout << "Simulation erfolgreich abgeschlossen.\n";
|
std::cout << "Simulation erfolgreich abgeschlossen.\n";
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
@ -4,19 +4,30 @@
|
||||||
#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;
|
std::vector<int> data; // Speicher für Elemente
|
||||||
size_t read_ptr = 0;
|
size_t read_ptr = 0; // Lesezeiger (nächstes zu lesendes Element)
|
||||||
size_t write_ptr = 0;
|
size_t write_ptr = 0; // Schreibzeiger (nächstes freie Position)
|
||||||
bool full = false;
|
bool full = false; // Flag, ob Puffer voll ist
|
||||||
|
|
||||||
std::mutex mtx;
|
// Synchronisationsprimitive
|
||||||
std::condition_variable not_empty;
|
std::mutex mtx; // Schützt alle internen Zustände
|
||||||
|
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;
|
||||||
}
|
}
|
||||||
|
|
@ -24,28 +35,56 @@ 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;
|
||||||
|
|
@ -53,11 +92,13 @@ 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;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
BIN
sensor_network
BIN
sensor_network
Binary file not shown.
|
|
@ -3,31 +3,43 @@
|
||||||
#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();
|
||||||
}
|
}
|
||||||
|
|
@ -39,18 +51,29 @@ 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);
|
std::uniform_int_distribution<> data_gen(0, 100); // Messwerte 0-100
|
||||||
std::uniform_int_distribution<> sleep_gen(100, 500);
|
std::uniform_int_distribution<> sleep_gen(100, 500); // Intervall 100-500ms
|
||||||
|
|
||||||
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);
|
||||||
|
|
||||||
|
|
@ -58,11 +81,22 @@ 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
|
||||||
|
|
@ -70,18 +104,27 @@ 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);
|
std::uniform_int_distribution<> update_gen(0, 100); // Modellwerte
|
||||||
std::uniform_int_distribution<> sleep_gen(500, 2000);
|
std::uniform_int_distribution<> sleep_gen(500, 2000); // Update-Intervall
|
||||||
|
|
||||||
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);
|
||||||
|
|
||||||
|
|
@ -89,6 +132,7 @@ 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>;
|
||||||
|
|
@ -5,12 +5,22 @@
|
||||||
#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;
|
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
|
||||||
|
|
||||||
|
// 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;
|
||||||
|
|
@ -24,7 +34,8 @@ 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();
|
||||||
};
|
};
|
||||||
Loading…
Add table
Add a link
Reference in a new issue