### 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