4.2 KiB
4.2 KiB
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
struct Task { int pid; // Prozess-ID std::string filename; // Dateiname des Tasks std::vector<std::pair<std::string, std::string>> 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
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
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:
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
READwird der Task für 2 Takte blockiert - EXE-Befehl: Startet neuen Task mit eigenem Programm
- Zeitscheibe: Task läuft maximal
time_sliceBefehle am Stück - IDLE: Wenn alle Tasks blockiert sind
std::cout << current_tick << "\tIDLE" << std::endl;
E. Statistik am Ende Ausgabe für jeden Task:
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:
// 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
readFileversucht 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
- Tick 0: Lädt
LOAD 5in init-Task - Tick 1: Führt
ADD 3aus (Akku=8) - Tick 2: Startet neuen Task aus file_a
- 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