Betriebssysteme: Drei einfache Teile. Teil 1: Einführung (Übersetzung)

Einführung in Betriebssysteme

Hallo, Habr! Ich möchte Ihnen eine Reihe von Übersetzungsartikeln einer interessanten Literatur vorstellen, die ich für bemerkenswert halte – OSTEP. In diesem Material wird die Funktionsweise von Unix-ähnlichen Betriebssystemen eingehend untersucht, insbesondere die Arbeit mit Prozessen, verschiedenen Planern, dem Speicher und anderen ähnlichen Komponenten, die ein modernes Betriebssystem ausmachen. Die Originale aller Materialien können Sie hier ansehen hier. Bitte beachten Sie, dass die Übersetzung unprofessionell (relativ frei) durchgeführt wurde, aber ich hoffe, dass ich den allgemeinen Sinn bewahrt habe.

Die Laborarbeiten zu diesem Thema finden Sie hier:
– Original: pages.cs.wisc.edu/~remzi/OSTEP/Homework/homework.html
– Original: github.com/remzi-arpacidusseau/ostep-code
– meine persönliche Anpassung: github.com/bykvaadm/OS/tree/master/ostep

Und Sie können auch meinen Kanal auf Telegramm =)

Funktionsweise des Programms

Was passiert, wenn ein Programm läuft? Das gestartete Programm führt eine einfache Aufgabe aus – es führt Anweisungen aus. Jede Sekunde werden Millionen und sogar möglicherweise Milliarden von Anweisungen vom Prozessor aus dem Arbeitsspeicher abgerufen, daraufhin dekodiert er sie (zum Beispiel erkennt er, zu welchem Typ diese Anweisungen gehören) und führt sie aus. Dies können das Addieren von zwei Zahlen, der Zugriff auf den Speicher, die Überprüfung von Bedingungen, der Übergang zu einer Funktion und so weiter sein. Nach der Ausführung einer Anweisung wechselt der Prozessor zur Ausführung der nächsten. Und so werden Anweisung für Anweisung ausgeführt, bis das Programm abgeschlossen ist.
Dieses Beispiel ist selbstverständlich vereinfacht betrachtet – tatsächlich ermöglicht moderne Hardware, um die Arbeit des Prozessors zu beschleunigen, das Ausführen von Anweisungen außerhalb der Reihenfolge, das Berechnen möglicher Ergebnisse, das gleichzeitige Ausführen von Anweisungen und ähnliche Tricks.

Die von Neumann'sche Rechnerarchitektur

Die vereinfachte Form der Arbeit, die wir beschrieben haben, ähnelt der von Neumann'schen Rechnerarchitektur. Von Neumann ist einer der Pioniere der Computersysteme und auch einer der Autoren der Spieltheorie. Während eines Programmdurchlaufs geschehen viele andere Ereignisse, es laufen zahlreiche andere Prozesse und externe Logik ab, deren Hauptziel es ist, den Start, den Betrieb und die Wartung des Systems zu vereinfachen.
Es gibt eine Reihe von Softwareprogrammen, die dafür verantwortlich sind, dass Programme einfach gestartet werden können (oder sogar mehrere Programme gleichzeitig ausgeführt werden können). Diese ermöglichen es den Programmen, denselben Speicher zu teilen und mit verschiedenen Geräten zu interagieren. Diese Software-Suite wird im Wesentlichen als Betriebssystem bezeichnet und seine Aufgaben umfassen die Überwachung der korrekten und effizienten Funktionsweise des Systems sowie die Bereitstellung einer einfachen Verwaltung dieses Systems.

Das Betriebssystem

Das Betriebssystem, kurz OS, ist ein Komplex miteinander verbundener Programme, die zur Verwaltung der Ressourcen eines Computers und zur Organisation der Interaktion des Benutzers mit dem Computer bestimmt sind..
Das OS erreicht seine Effizienz in erster Linie durch die wichtigste Technik – die Technik der Virtualisierung. Das OS interagiert mit physischen Ressourcen (wie Prozessor, Speicher, Festplatte und ähnlichem) und transformiert sie in eine allgemeinere, leistungsfähigere und benutzerfreundlichere Form. Daher kann das Betriebssystem sehr grob mit einer virtuellen Maschine verglichen werden.
Um den Benutzern zu ermöglichen, dem Betriebssystem Befehle zu erteilen und somit die Möglichkeiten der virtuellen Maschine zu nutzen (wie z.B.: Programmstart, Speicherzuweisung, Dateizugriff usw.), stellt das Betriebssystem eine Schnittstelle zur Verfügung, die als API (Application Programming Interface) bekannt ist und bei der Aufrufe (Calls) gemacht werden können. Ein typisches Betriebssystem bietet Hunderte von Systemaufrufen an.
Und schließlich, da die Virtualisierung es einer Vielzahl von Programmen erlaubt, gleichzeitig zu arbeiten (damit das CPU gemeinsam genutzt wird), und gleichzeitig auf deren Anweisungen und Daten zuzugreifen (dabei den Speicher zu teilen) sowie auf Festplatten zuzugreifen (damit die Ein- und Ausgabegeräte gemeinsam genutzt werden), wird das Betriebssystem auch als Ressourcenmanager bezeichnet. Jeder Prozessor, jede Festplatte und jeder Speicher ist eine Ressource des Systems und somit wird eine der Rollen des Betriebssystems die Aufgabe, diese Ressourcen effektiv und fair oder, je nach Anforderung, für die das Betriebssystem entwickelt wurde, zu verwalten.

CPU-Virtualisierung

Betrachten wir das folgende Programm:
(https://www.youtube.com/watch?v=zDwT5fUcki4&feature=youtu.be)

Betriebssysteme: Drei einfache Teile. Teil 1: Einführung (Übersetzung)

Es führt keine besonderen Aktionen aus, im Grunde genommen ruft es nur die Funktion spin() auf, deren Aufgabe es ist, die Zeit zyklisch zu überprüfen und zurückzukehren, nachdem eine Sekunde vergangen ist. Somit wiederholt es endlos die Zeichenkette, die der Benutzer als Argument übergeben hat.
Lassen Sie uns dieses Programm starten und als Argument das Zeichen “A” übergeben. Das Ergebnis ist nicht besonders interessant – das System führt einfach das Programm aus, das periodisch das Zeichen “A” auf dem Bildschirm anzeigt.
Jetzt versuchen wir eine Variante, bei der mehrere Instanzen desselben Programms laufen, allerdings mit unterschiedlichen Buchstaben, um es verständlicher zu machen. In diesem Fall wird das Ergebnis etwas anders sein. Obwohl wir nur einen Prozessor haben, wird das Programm gleichzeitig ausgeführt. Wie kommt es dazu? Es liegt daran, dass das Betriebssystem, mit Hilfe der Hardwarefähigkeiten, eine Illusion schafft. Die Illusion, dass das System mehrere virtuelle Prozessoren hat, die einen physischen Prozessor in eine theoretisch unbegrenzte Anzahl verwandeln und somit den Programmen erlauben, gleichzeitig zu erscheinen. Diese Illusion nennt man CPU-Virtualisierung.
Ein solches Szenario wirft viele Fragen auf, zum Beispiel, wenn mehrere Programme gleichzeitig gestartet werden möchten, welches wird tatsächlich gestartet? Diese Frage beantworten die “Politiken” des Betriebssystems. Politiken werden an vielen Stellen im Betriebssystem verwendet und beantworten solche Fragen; sie sind auch grundlegende Mechanismen, die das Betriebssystem implementiert. Daher die Rolle des Betriebssystems als Ressourcenmanager.

Speicher-Virtualisierung

Jetzt lassen Sie uns den Speicher betrachten. Das physische Modell des Speichers in modernen Systemen wird als Array von Bytes dargestellt. Um aus dem Speicher zu lesen, muss man die Adresse der Zelle, um darauf zuzugreifen. Um Daten zu schreiben oder zu aktualisieren, müssen auch die Daten und die Adresse der Zelle angegeben werden, in die sie geschrieben werden sollen.
Zugriffe auf den Speicher erfolgen ständig während der Ausführung des Programms. Das Programm speichert seine gesamte Datenstruktur im Speicher und greift darauf zu, während es verschiedene Anweisungen ausführt. Die Anweisungen selbst werden ebenfalls im Speicher gespeichert, weshalb auf diesen auch bei jedem Anfrage zur nächsten Anweisung zugegriffen wird.

Der Aufruf von malloc()

Betrachten wir das folgende Programm, das Speicherbereiche durch einen Aufruf reserviert malloc() (https://youtu.be/jnlKRnoT1m0):

Betriebssysteme: Drei einfache Teile. Teil 1: Einführung (Übersetzung)

Das Programm macht mehrere Dinge. Zunächst reserviert es einen bestimmten Speicherbereich (Zeile 7), gibt dann die Adresse der reservierten Zelle aus (Zeile 9) und schreibt null in den ersten Slot des reservierten Speichers. Danach geht das Programm in eine Schleife, in der es den Wert inkrementiert, der im Speicher an der Adresse der Variable „p“ gespeichert ist. Außerdem gibt es die Prozess-ID von sich selbst aus. Die Prozess-ID ist für jeden ausgeführten Prozess einzigartig. Wenn wir jedoch mehrere Kopien starten, stoßen wir auf ein interessantes Ergebnis: Im ersten Fall, wenn wir nichts tun und einfach mehrere Kopien starten, sind die Adressen unterschiedlich. Aber das passt nicht zu unserer Theorie! Richtig, denn in modernen Distributionen ist standardmäßig eine Funktion zur Randomisierung des Speichers aktiviert. Wenn wir diese deaktivieren, erhalten wir das erwartete Ergebnis – die Speicheradressen von zwei gleichzeitig ausgeführten Programmen werden identisch sein.

Betriebssysteme: Drei einfache Teile. Teil 1: Einführung (Übersetzung)

Insgesamt ergibt sich, dass zwei unabhängige Programme mit ihren eigenen privaten Adressräumen arbeiten, die wiederum von dem Betriebssystem in den physischen Speicher abgebildet werden. Daher beeinflusst die Nutzung von Speicheradressen innerhalb eines Programms andere nicht, und jedem Programm scheint, dass es über einen eigenen physischen Speicherbereich verfügt, der vollständig in seinem Ermessen ist. Die Realität jedoch ist, dass physischer Speicher eine gemeinsame Ressource ist, deren Verwaltung vom Betriebssystem übernommen wird.

Konsistenz

Ein weiteres wichtiges Thema im Rahmen von Betriebssystemen ist die Kohärenz. Dieser Begriff wird verwendet, wenn es um Probleme im System geht, die auftreten können, wenn viele Dinge gleichzeitig innerhalb eines Programms bearbeitet werden. Kohärenzprobleme treten sogar im Betriebssystem selbst auf. In den vorherigen Beispielen mit der Virtualisierung von Speicher und Prozessor haben wir verstanden, dass das Betriebssystem viele Dinge gleichzeitig verwaltet – den ersten Prozess startet, dann den zweiten und so weiter. Wie sich herausgestellt hat, kann ein solches Verhalten zu bestimmten Problemen führen. So haben moderne Multithread-Programme mit solchen Schwierigkeiten zu kämpfen.

Betrachten wir das folgende Programm:

Betriebssysteme: Drei einfache Teile. Teil 1: Einführung (Übersetzung)

Das Programm in der Hauptfunktion erstellt zwei Threads, indem es einen Aufruf verwendet Pthread_create(). In diesem Beispiel kann man einen Thread als eine Funktion betrachten, die in einem gemeinsamen Speicherbereich neben anderen Funktionen ausgeführt wird, wobei die Anzahl der gleichzeitig ausgeführten Funktionen offensichtlich mehr als eins beträgt. In diesem Beispiel startet jeder Thread und führt die Funktion worker() aus, die ihrerseits einfach eine Variable inkrementiert.,.

Wir starten dieses Programm mit dem Argument 1000. Wie Sie sich vielleicht schon gedacht haben, sollte das Ergebnis 2000 sein, da jeder Thread die Variable 1000 Mal inkrementiert hat. Doch es ist nicht so einfach. Lassen Sie uns das Programm mit einer Anzahl von Wiederholungen bei einer Ordnung größer versuchen.

Betriebssysteme: Drei einfache Teile. Teil 1: Einführung (Übersetzung)

Wenn wir eine Zahl wie 100000 eingeben, erwarten wir, dass wir als Ausgabe die Zahl 200000 sehen. Wenn wir jedoch die Zahl 100000 mehrmals ausführen, werden wir nicht nur das richtige Ergebnis nicht sehen, sondern auch verschiedene falsche Antworten erhalten. Das Rätsel liegt darin, dass zum Erhöhen der Zahl drei Operationen erforderlich sind – das Auslesen der Zahl aus dem Speicher, das Inkrementieren und dann das Zurückschreiben der Zahl. Da all diese Anweisungen nicht atomar (also nicht gleichzeitig) durchgeführt werden, können solche merkwürdigen Dinge passieren. Dieses Problem wird in der Programmierung als race condition – Zustand des Wettlaufs. Wenn unbekannte Kräfte zu unbekannten Zeitpunkten die Ausführung Ihrer Operationen beeinflussen können.

Quelle: habr.com

Zuverlässiges Hosting für Websites mit DDoS-Schutz kaufen, VPS VDS Server 🔥 Zuverlässiges Hosting für Websites mit DDoS-Schutz kaufen, VPS VDS Server - ProHoster