Compare commits
1 commit
| Author | SHA1 | Date | |
|---|---|---|---|
| efd4e8fdf5 |
4 changed files with 65 additions and 336 deletions
133
README.md
133
README.md
|
|
@ -1,133 +0,0 @@
|
||||||
### 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<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**
|
|
||||||
```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
|
|
||||||
|
|
||||||
225
einlesen.cpp
225
einlesen.cpp
|
|
@ -1,228 +1,47 @@
|
||||||
#include <iostream>
|
#include "task.h"
|
||||||
#include <fstream>
|
#include <deque>
|
||||||
#include <string>
|
|
||||||
#include <vector>
|
|
||||||
#include <utility>
|
|
||||||
#include <sstream>
|
|
||||||
#include <cstdlib>
|
|
||||||
#include <ctime>
|
|
||||||
#include <algorithm>
|
|
||||||
#include <iomanip>
|
|
||||||
|
|
||||||
struct Task {
|
using namespace std;
|
||||||
int pid;
|
|
||||||
std::string filename;
|
|
||||||
std::vector<std::pair<std::string, std::string>> program;
|
|
||||||
int pc;
|
|
||||||
int accu;
|
|
||||||
int blocked;
|
|
||||||
int start_tick;
|
|
||||||
int end_tick;
|
|
||||||
bool terminated;
|
|
||||||
int slice_remaining;
|
|
||||||
};
|
|
||||||
|
|
||||||
std::vector<std::pair<std::string, std::string>> readFile(const std::string &filename) {
|
vector<pair<string, string> > readFile(const string &filename) {
|
||||||
std::vector<std::pair<std::string, std::string>> instructions;
|
vector<pair<string, string> > instructions;
|
||||||
std::ifstream file(filename);
|
ifstream file(filename);
|
||||||
if(!file.is_open()) {
|
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;
|
return instructions;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string line;
|
string line;
|
||||||
while (std::getline(file, line)) {
|
while (getline(file, line)) {
|
||||||
|
// Entferne führende oder trailing Whitespace
|
||||||
if (line.empty()) continue;
|
if (line.empty()) continue;
|
||||||
|
|
||||||
std::istringstream iss(line);
|
istringstream iss(line);
|
||||||
std::string command;
|
string command;
|
||||||
std::string param;
|
string param;
|
||||||
|
|
||||||
if (!(iss >> command)) {
|
if (!(iss >> command)) {
|
||||||
|
// Keine gültige Eingabe in dieser Zeile
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Optionalen Parameter einlesen, falls vorhanden
|
||||||
if (!(iss >> param)) {
|
if (!(iss >> param)) {
|
||||||
|
// Kein Parameter vorhanden
|
||||||
param = "";
|
param = "";
|
||||||
}
|
}
|
||||||
|
|
||||||
instructions.push_back(std::make_pair(command, param));
|
instructions.push_back(make_pair(command, param));
|
||||||
}
|
}
|
||||||
|
|
||||||
return instructions;
|
return instructions;
|
||||||
}
|
}
|
||||||
|
|
||||||
int main(int argc, char* argv[]) {
|
// Beispiel zur Nutzung
|
||||||
if (argc < 2) {
|
int main() {
|
||||||
std::cerr << "Verwendung: " << argv[0] << " <Zeitscheibenlänge>" << std::endl;
|
auto result = readFile("init");
|
||||||
return 1;
|
for (const auto &inst : result) {
|
||||||
}
|
cout << "Befehl: " << inst.first << " | Parameter: " << inst.second << "\n";
|
||||||
int time_slice = std::stoi(argv[1]);
|
|
||||||
srand(time(0));
|
|
||||||
|
|
||||||
std::vector<Task> 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;
|
return 0;
|
||||||
|
|
|
||||||
15
task.cpp
Normal file
15
task.cpp
Normal file
|
|
@ -0,0 +1,15 @@
|
||||||
|
#include <task.h>
|
||||||
|
|
||||||
|
Task::Task(int pid,
|
||||||
|
const std::string &name,
|
||||||
|
const std::vector<std::pair<std::string, std::string>> &program)
|
||||||
|
{
|
||||||
|
this->pid=pid;
|
||||||
|
this->name=name;
|
||||||
|
this->program=program;
|
||||||
|
this->pc=0;
|
||||||
|
this->acc=0;
|
||||||
|
this->blockTicks=0;
|
||||||
|
this->active=true;
|
||||||
|
}
|
||||||
|
|
||||||
28
task.h
Normal file
28
task.h
Normal file
|
|
@ -0,0 +1,28 @@
|
||||||
|
#ifndef TASK_H
|
||||||
|
#define TASK_H
|
||||||
|
|
||||||
|
#include <iostream>
|
||||||
|
#include <iomanip>
|
||||||
|
#include <fstream>
|
||||||
|
#include <string>
|
||||||
|
#include <vector>
|
||||||
|
#include <utility>
|
||||||
|
#include <sstream>
|
||||||
|
|
||||||
|
class Task
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
Task()=delete;
|
||||||
|
Task(int pid, const std::string &name, const std::vector<std::pair<std::string, std::string>> &program);
|
||||||
|
private:
|
||||||
|
int pid,
|
||||||
|
pc,
|
||||||
|
acc,
|
||||||
|
blockTicks;
|
||||||
|
std::string name;
|
||||||
|
std::vector<std::pair<std::string, std::string>> program;
|
||||||
|
bool active;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
#endif //TASK_H
|
||||||
Loading…
Add table
Add a link
Reference in a new issue