From 03ec564fa12a3fc1acfad897770b05acc5ac8867 Mon Sep 17 00:00:00 2001 From: portnoytmy Date: Mon, 16 Jun 2025 10:12:02 +0200 Subject: [PATCH 1/3] =?UTF-8?q?Musterl=C3=B6sung=20oder=20so?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .gitignore | 30 ++++++++ CMakeLists.txt | 25 ++++++ einlesen.cpp | 201 ++++++++++++++++++++++++++++++++++++++++++++++--- 3 files changed, 245 insertions(+), 11 deletions(-) create mode 100644 .gitignore create mode 100644 CMakeLists.txt diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..80ccb77 --- /dev/null +++ b/.gitignore @@ -0,0 +1,30 @@ +# Build-Verzeichnisse +build/ +bin/ +lib/ + +# CMake-Dateien +CMakeFiles/ +CMakeCache.txt +cmake_install.cmake +Makefile + +# Compiled Object files +*.o +*.obj + +# Shared objects +*.so +*.dylib +*.dll + +# Executables +*.exe +*.out +*.app + +# IDE-spezifische Dateien +.vscode/ +.idea/ +*.swp +*~ diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 0000000..0233e40 --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,25 @@ +cmake_minimum_required(VERSION 3.10) +project(BS_Praktikum5 VERSION 0.1.0 LANGUAGES CXX) + +# Compiler-Optionen +set(CMAKE_CXX_STANDARD 17) +set(CMAKE_CXX_STANDARD_REQUIRED ON) +set(CMAKE_CXX_EXTENSIONS OFF) + +# Warnungen und Debug-Informationen bei Entwicklung aktivieren +if(CMAKE_BUILD_TYPE STREQUAL "Debug") + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Wextra -Wpedantic -g") +endif() + +# Aktuelles Verzeichnis als Include-Pfad hinzufügen +include_directories(.) + +# Quellen sammeln +file(GLOB SOURCES *.cpp) +file(GLOB HEADERS *.h *.hpp) + +# Ausführbare Datei erstellen +add_executable(${PROJECT_NAME} ${SOURCES}) + +# Installation konfigurieren +install(TARGETS ${PROJECT_NAME} DESTINATION bin) diff --git a/einlesen.cpp b/einlesen.cpp index c219a30..4883f9f 100644 --- a/einlesen.cpp +++ b/einlesen.cpp @@ -4,9 +4,26 @@ #include #include #include +#include +#include +#include +#include -std::vector > readFile(const std::string &filename) { - std::vector > instructions; +struct Task { + int pid; + std::string filename; + std::vector> program; + int pc; + int accu; + int blocked; + int start_tick; + int end_tick; + bool terminated; + int slice_remaining; +}; + +std::vector> readFile(const std::string &filename) { + std::vector> instructions; std::ifstream file(filename); if(!file.is_open()) { std::cerr << "Fehler: Datei " << filename << " konnte nicht geöffnet werden.\n"; @@ -15,7 +32,6 @@ std::vector > readFile(const std::string &fi std::string line; while (std::getline(file, line)) { - // Entferne führende oder trailing Whitespace if (line.empty()) continue; std::istringstream iss(line); @@ -23,13 +39,10 @@ std::vector > readFile(const std::string &fi std::string param; if (!(iss >> command)) { - // Keine gültige Eingabe in dieser Zeile continue; } - // Optionalen Parameter einlesen, falls vorhanden if (!(iss >> param)) { - // Kein Parameter vorhanden param = ""; } @@ -39,11 +52,177 @@ std::vector > readFile(const std::string &fi return instructions; } -// Beispiel zur Nutzung -int main() { - auto result = readFile("init"); - for (const auto &inst : result) { - std::cout << "Befehl: " << inst.first << " | Parameter: " << inst.second << "\n"; +int main(int argc, char* argv[]) { + if (argc < 2) { + std::cerr << "Verwendung: " << argv[0] << " " << std::endl; + return 1; + } + int time_slice = std::stoi(argv[1]); + srand(time(0)); + + std::vector tasks; + int next_pid = 0; + int current_tick = 0; + + // Initialen Task aus init erstellen + auto init_program = readFile("init"); + if (init_program.empty()) { + std::cerr << "Fehler: init konnte nicht gelesen werden." << std::endl; + return 1; + } + Task init_task = { + next_pid++, + "init", + init_program, + 0, + 0, + 0, + 0, + -1, + false, + time_slice + }; + tasks.push_back(init_task); + + // Header ausgeben + std::cout << "Tick\tPID\tTask\tPC\tAccu\tInstr" << std::endl; + + int last_executed_index = -1; + bool all_terminated = false; + + while (!all_terminated) { + all_terminated = true; + bool found_runnable = false; + int start_index = (last_executed_index + 1) % tasks.size(); + int current_index = start_index; + Task* current_task = nullptr; + + do { + Task& task = tasks[current_index]; + if (!task.terminated && task.blocked == 0) { + current_task = &task; + found_runnable = true; + last_executed_index = current_index; + break; + } + current_index = (current_index + 1) % tasks.size(); + } while (current_index != start_index); + + if (found_runnable) { + while (current_task->slice_remaining > 0 && !current_task->terminated && current_task->blocked == 0) { + // Hole Befehl + auto& instruction = current_task->program[current_task->pc]; + std::string command = instruction.first; + std::string param = instruction.second; + + // Ausgabe des aktuellen Zustands + std::cout << current_tick << "\t" + << current_task->pid << "\t" + << current_task->filename << "\t" + << current_task->pc << "\t" + << current_task->accu << "\t" + << command; + if (!param.empty()) { + std::cout << " " << param; + } + std::cout << std::endl; + + // Führe Befehl aus + if (command == "LOAD") { + current_task->accu = std::stoi(param); + } else if (command == "ADD") { + current_task->accu += std::stoi(param); + } else if (command == "SUB") { + current_task->accu -= std::stoi(param); + } else if (command == "READ") { + current_task->accu = rand() % 4096; + current_task->blocked = 2; + } else if (command == "EXE") { + std::string filename = param; + auto new_program = readFile(filename); + if (!new_program.empty()) { + Task new_task = { + next_pid++, + param, + new_program, + 0, + 0, + 0, + current_tick + 1, + -1, + false, + time_slice + }; + tasks.push_back(new_task); + } + } else if (command == "T") { + current_task->terminated = true; + current_task->end_tick = current_tick; + } + + // PC erhöhen, außer bei Terminierung + if (command != "T") { + current_task->pc++; + if (current_task->pc >= current_task->program.size()) { + current_task->terminated = true; + current_task->end_tick = current_tick; + } + } + + // Blockierungszeit für andere Tasks dekrementieren + for (auto& task : tasks) { + if (task.blocked > 0) { + if (&task == current_task && command == "READ") { + // Nicht dekrementieren + } else { + task.blocked--; + } + } + } + + // Zeitscheibe verbrauchen + current_task->slice_remaining--; + current_tick++; + + // Bei Blockierung oder Terminierung Schleife verlassen + if (current_task->blocked > 0 || current_task->terminated) { + break; + } + } + + // Zeitscheibe zurücksetzen + current_task->slice_remaining = time_slice; + } else { + // Kein lauffähiger Task (IDLE) + std::cout << current_tick << "\tIDLE" << std::endl; + for (auto& task : tasks) { + if (task.blocked > 0) { + task.blocked--; + } + } + current_tick++; + } + + // Prüfen, ob noch aktive Tasks existieren + for (const auto& task : tasks) { + if (!task.terminated) { + all_terminated = false; + break; + } + } + } + + // Statistik ausgeben + std::cout << "\nStatistik:" << std::endl; + std::cout << "PID\tTask\tStart\tEnde\tVerweilzeit\tAccu" << std::endl; + for (const auto& task : tasks) { + int turnaround = task.end_tick - task.start_tick + 1; + std::cout << task.pid << "\t" + << task.filename << "\t" + << task.start_tick << "\t" + << task.end_tick << "\t" + << turnaround << "\t\t" + << task.accu << std::endl; } return 0; From ebf9170ca7687d8e59f697175ee4249471c7cec1 Mon Sep 17 00:00:00 2001 From: portnoytmy Date: Mon, 16 Jun 2025 10:25:44 +0200 Subject: [PATCH 2/3] README with explanations added --- README.md | 133 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 133 insertions(+) create mode 100644 README.md diff --git a/README.md b/README.md new file mode 100644 index 0000000..f125f62 --- /dev/null +++ b/README.md @@ -0,0 +1,133 @@ +### Erklärung des Programms und seiner Funktionsweise + +#### 1. Grundlegende Struktur +Das Programm simuliert einen präemptiven Scheduler nach dem Round-Robin-Prinzip für einen Mikrocontroller. Es verwaltet mehrere Tasks (Prozesse), die aus Dateien gelesen werden und abwechselnd Rechenzeit erhalten. + +#### 2. Wichtige Komponenten +- **Task-Struktur**: Repräsentiert einen Prozess + ```cpp + struct Task { + int pid; // Prozess-ID + std::string filename; // Dateiname des Tasks + std::vector> program; // Befehlsliste + int pc; // Program Counter + int accu; // Akkumulator-Wert + int blocked; // Verbleibende Blockierungszeit + int start_tick; // Startzeitpunkt + int end_tick; // Endzeitpunkt + bool terminated; // Status ob beendet + int slice_remaining; // Verbleibende Zeitscheibenzeit + }; + ``` + +#### 3. Ablauf des Programms + +**A. Initialisierung** +```cpp +auto init_program = readFile("init"); // Liest init-Datei OHNE .txt +Task init_task = { + next_pid++, // PID 0 + "init", // Dateiname + init_program, // Programmcode + 0, // PC startet bei 0 + 0, // Akku startet bei 0 + 0, // Nicht blockiert + 0, // Start bei Tick 0 + -1, // Ende noch nicht bekannt + false, // Noch nicht terminiert + time_slice // Volle Zeitscheibe +}; +tasks.push_back(init_task); +``` + +**B. Hauptschleife - Der Scheduler** +```cpp +while (!all_terminated) { + // 1. Suche nächsten ausführbaren Task (Round-Robin) + // 2. Führe Task aus (so lange Zeitscheibe reicht) + // 3. Verarbeite Blockierungszeiten + // 4. Prüfe auf Terminierung +} +``` + +**C. Task-Ausführung** +Für jeden Befehl: +```cpp +if (command == "LOAD") { + current_task->accu = std::stoi(param); +} else if (command == "ADD") { + current_task->accu += std::stoi(param); +} else if (command == "SUB") { + current_task->accu -= std::stoi(param); +} else if (command == "READ") { + current_task->accu = rand() % 4096; // Zufallswert 0-4095 + current_task->blocked = 2; // 2 Takte blockieren +} else if (command == "EXE") { + // NEU: Direkt param verwenden OHNE .txt + std::string filename = param; + auto new_program = readFile(filename); + // Neuen Task erstellen und hinzufügen +} else if (command == "T") { + current_task->terminated = true; +} +``` + +**D. Besondere Logik** +- **Blockierung**: Bei `READ` wird der Task für 2 Takte blockiert +- **EXE-Befehl**: Startet neuen Task mit eigenem Programm +- **Zeitscheibe**: Task läuft maximal `time_slice` Befehle am Stück +- **IDLE**: Wenn alle Tasks blockiert sind + ```cpp + std::cout << current_tick << "\tIDLE" << std::endl; + ``` + +**E. Statistik am Ende** +Ausgabe für jeden Task: +```cpp +PID Task Start Ende Verweilzeit Akku +0 init 0 12 13 7 +1 file_a 3 8 6 19 +... +``` + +#### 4. Durchgeführte Änderungen +Ihre Anpassungen sind hier besonders wichtig: +```cpp +// Vorher: "init.txt" -> Jetzt: "init" +auto init_program = readFile("init"); + +// Vorher: param + ".txt" -> Jetzt: direkt param +std::string filename = param; +auto new_program = readFile(filename); +``` + +**Begründung**: +- Die Aufgabenstellung gibt Dateien ohne `.txt`-Erweiterung vor (init, file_a, etc.) +- Die Funktion `readFile` versucht direkt den übergebenen Namen zu öffnen +- Ohne Änderung würde das Programm nach nicht existierenden Dateien suchen (z.B. "file_a.txt" statt "file_a") + +#### 5. Beispielablauf +Für init.txt mit: +``` +LOAD 5 +ADD 3 +EXE file_a +``` + +1. Tick 0: Lädt `LOAD 5` in init-Task +2. Tick 1: Führt `ADD 3` aus (Akku=8) +3. Tick 2: Startet neuen Task aus file_a +4. Abwechselnde Ausführung beider Tasks + +#### 6. Besondere Szenarien +- **Alle Tasks blockiert**: + - Scheduler gibt "IDLE" aus + - Blockierungszeiten werden dekrementiert +- **EXE in mehreren Tasks**: + - Neue Tasks werden sofort zur Ausführung hinzugefügt + - Können vor dem Eltern-Task terminieren +- **Zeitscheibe zu Ende**: + - Task wird unterbrochen (präemptiv) + - Zustand (PC, Akku) wird gespeichert + - Nächster Task in Round-Robin-Reihenfolge kommt dran + From efd4e8fdf579ff6ba2e84cb623adc1a1accbb293 Mon Sep 17 00:00:00 2001 From: portnoytmy Date: Mon, 16 Jun 2025 23:47:53 +0200 Subject: [PATCH 3/3] added task-class --- .gitignore | 30 ++++++++++++++++++++++++++++++ CMakeLists.txt | 25 +++++++++++++++++++++++++ einlesen.cpp | 32 +++++++++++++++----------------- task.cpp | 15 +++++++++++++++ task.h | 28 ++++++++++++++++++++++++++++ 5 files changed, 113 insertions(+), 17 deletions(-) create mode 100644 .gitignore create mode 100644 CMakeLists.txt create mode 100644 task.cpp create mode 100644 task.h diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..80ccb77 --- /dev/null +++ b/.gitignore @@ -0,0 +1,30 @@ +# Build-Verzeichnisse +build/ +bin/ +lib/ + +# CMake-Dateien +CMakeFiles/ +CMakeCache.txt +cmake_install.cmake +Makefile + +# Compiled Object files +*.o +*.obj + +# Shared objects +*.so +*.dylib +*.dll + +# Executables +*.exe +*.out +*.app + +# IDE-spezifische Dateien +.vscode/ +.idea/ +*.swp +*~ diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 0000000..0233e40 --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,25 @@ +cmake_minimum_required(VERSION 3.10) +project(BS_Praktikum5 VERSION 0.1.0 LANGUAGES CXX) + +# Compiler-Optionen +set(CMAKE_CXX_STANDARD 17) +set(CMAKE_CXX_STANDARD_REQUIRED ON) +set(CMAKE_CXX_EXTENSIONS OFF) + +# Warnungen und Debug-Informationen bei Entwicklung aktivieren +if(CMAKE_BUILD_TYPE STREQUAL "Debug") + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Wextra -Wpedantic -g") +endif() + +# Aktuelles Verzeichnis als Include-Pfad hinzufügen +include_directories(.) + +# Quellen sammeln +file(GLOB SOURCES *.cpp) +file(GLOB HEADERS *.h *.hpp) + +# Ausführbare Datei erstellen +add_executable(${PROJECT_NAME} ${SOURCES}) + +# Installation konfigurieren +install(TARGETS ${PROJECT_NAME} DESTINATION bin) diff --git a/einlesen.cpp b/einlesen.cpp index c219a30..9487db0 100644 --- a/einlesen.cpp +++ b/einlesen.cpp @@ -1,26 +1,24 @@ -#include -#include -#include -#include -#include -#include +#include "task.h" +#include -std::vector > readFile(const std::string &filename) { - std::vector > instructions; - std::ifstream file(filename); +using namespace std; + +vector > readFile(const string &filename) { + vector > instructions; + ifstream file(filename); if(!file.is_open()) { - std::cerr << "Fehler: Datei " << filename << " konnte nicht geöffnet werden.\n"; + cerr << "Fehler: Datei " << filename << " konnte nicht geöffnet werden.\n"; return instructions; } - std::string line; - while (std::getline(file, line)) { + string line; + while (getline(file, line)) { // Entferne führende oder trailing Whitespace if (line.empty()) continue; - std::istringstream iss(line); - std::string command; - std::string param; + istringstream iss(line); + string command; + string param; if (!(iss >> command)) { // Keine gültige Eingabe in dieser Zeile @@ -33,7 +31,7 @@ std::vector > readFile(const std::string &fi param = ""; } - instructions.push_back(std::make_pair(command, param)); + instructions.push_back(make_pair(command, param)); } return instructions; @@ -43,7 +41,7 @@ std::vector > readFile(const std::string &fi int main() { auto result = readFile("init"); for (const auto &inst : result) { - std::cout << "Befehl: " << inst.first << " | Parameter: " << inst.second << "\n"; + cout << "Befehl: " << inst.first << " | Parameter: " << inst.second << "\n"; } return 0; diff --git a/task.cpp b/task.cpp new file mode 100644 index 0000000..222621f --- /dev/null +++ b/task.cpp @@ -0,0 +1,15 @@ +#include + +Task::Task(int pid, + const std::string &name, + const std::vector> &program) +{ + this->pid=pid; + this->name=name; + this->program=program; + this->pc=0; + this->acc=0; + this->blockTicks=0; + this->active=true; +} + diff --git a/task.h b/task.h new file mode 100644 index 0000000..b0f775e --- /dev/null +++ b/task.h @@ -0,0 +1,28 @@ +#ifndef TASK_H +#define TASK_H + +#include +#include +#include +#include +#include +#include +#include + +class Task +{ +public: + Task()=delete; + Task(int pid, const std::string &name, const std::vector> &program); +private: + int pid, + pc, + acc, + blockTicks; + std::string name; + std::vector> program; + bool active; +}; + + +#endif //TASK_H