Betriebssysteme

Programmiersprachen, APIs, Bibliotheken, Open Source Engines, Debugging, Quellcode Fehler und alles was mit praktischer Programmierung zu tun hat.
Antworten
Benutzeravatar
starcow
Establishment
Beiträge: 523
Registriert: 23.04.2003, 17:42
Echter Name: Mischa Schaub
Kontaktdaten:

Betriebssysteme

Beitrag von starcow »

Abend zusammen

Ich merke, dass ich irgendwie nicht wirklich eine klare Vorstellung davon habe, was die eigentliche Funktion des Betriebssystems ist.
Das Betriebssystem ist doch eigentlich auch "nur" ein Programm, oder? Klar, ich habe damit eine Art Grundpalette von Programmen und z.B. meine Dateien organisieren zu können.
Aber was passiert denn eigentlich wenn ich ein Programm in C oder C++ schreibe, dieses kompiliere und ausführe? Sind das denn nun Instruktionen für die Hardware (übersetzt in 0 und 1) oder sind das tatsächlich nur Befehle für das Betriebssystem?

Davon abgesehen, was denkt ihr, wie gut man sich mit der Betriebssystem-Programmierung auskennen sollte, wenn man denn Spiele entwickeln will?
Macht das Sinn in diesem Kontext, sich in diese Materie einzuarbeiten?

Gruss, starcow
Freelancer 3D- und 2D-Grafik
mischaschaub.com
Spiele Programmierer
Establishment
Beiträge: 426
Registriert: 23.01.2013, 15:55

Re: Betriebssysteme

Beitrag von Spiele Programmierer »

Wenn du ein C(++) Programm schreibst, wird dies in Prozessorcode übersetzt. Normalerweise ist das x86 am PC. Mit einem Disassembler (oder mit dem richtigen Flag fest in die meisten Compiler eingebaut), kannst du diesen in Assemblercode umwandeln. Assemblercode korrespondiert i.d.R. 1:1 zu den Bytes die tatsächlich in einer *.exe/*.dll/*.so-Datei stehen, nur halt etwas praktischer zu lesen als 0xff 0x6a. Mit dieser praktischen Seite, kannst du auch schauen, was der Compiler macht: https://gcc.godbolt.org/. (Wenn du in den "Output..."-Optionen rechts noch "Compile to binary" anhakst, kriegst du auch noch die exakten Bytes denen das entspricht.)

Was dein Prozessor so alles kann, wird vom Hersteller dokumentiert und es gibt diverse Resourcen dazu. Ich glaube zum Einarbeiten ist das nicht so geeignet, aber so als groben Überblick kannst du z.B. auf Wikipedia gucken: https://en.wikipedia.org/wiki/X86_instruction_listings. Das bedeutet, dass rein theoretisch der gleiche Code tatsächlich betriebssystemunabhängig ist. Der Prozessor macht sowohl mit Windows, Linux, FreeBSD, Solaris und MacOSX das selbe.

Das Betriebssystem kommt vor allem über zwei Wege ins Spiel:
  • Irgendwie müssen die Maschinenbefehle von der Festplatte in den RAM kommen. Das macht das Betriebssystem und zudem sind zum Beispiel das windowsche PE-Format (*.exe) und das linuxsche Elf-Format (*.so) unterschiedlich! D.h. hier gibt es dann leider erste Inkompatbilitäten, da in den Formaten oft noch unterschiedliche Metainformationen gespeichert werden, wie z.B. wieviel RAM anfänglich bereitgestellt werden soll, welche Bibliotheken schon mitgeladen werden sollen oder ein Icon. Das sehr veraltete *.com-Format, das mit 32-Bit-Windows-Versionen immernoch ausführbar ist, beinhaltet dagegen wirklich *nur* den Maschinencode für den Prozessor, so wie man ihn z.B. bei der Godbolt-Seite sehen kann.
  • Wenn das Programm irgendwas rechnen kann, ist das schonmal gut, aber am Ende sollten die Ergebnisse auch irgendwie aus dem Programm herauskommen. Sonst war die Rechnung für die Katz. Zum Beispiel kann man dann irgendwas in die Konsole schicken oder in eine Datei schreiben. Optimalerweise willst du wahrscheinlich auch noch eine Eingabe! Also z.B. von der Tastatur oder auch aus irgendwelchen Dateien. All das ist Teil des Betriebssystem.
Als ziemlich gute Faustregel kann man sagen, dass alle Rechnungen Zuständigkeit des Prozessors sind und alles was irgendwie mit der Umgebung zu tun hat (durch irgendeine Form von Ein- oder Ausgabe) vom Betriebssystem bereitgestellt wird. Um zum Beispiel zu sehen, was Windows hier anbietet, kannst du die Seite von Microsoft konsultieren: https://docs.microsoft.com/en-us/window ... s-api-list.

Wenn du diese Funktionen nicht selbst direkt benützt, wird das wahrscheinlich von den von dir verwendeten Bibliotheken getan. Zum Beispiel fopen der C-Standardbibliothek geht intern auch nur weiter an CreateFile der Windows-API.
starcow hat geschrieben: 29.01.2021, 19:37 Davon abgesehen, was denkt ihr, wie gut man sich mit der Betriebssystem-Programmierung auskennen sollte, wenn man denn Spiele entwickeln will?
Macht das Sinn in diesem Kontext, sich in diese Materie einzuarbeiten?
Auskennen müssen? Ich denke gar nicht. Andererseits hilft es bestimmt hier und da ein bisschen.

Vor inzwischen fast 10 Jahren habe ich mal ein bisschen mit Betriebssystemprogrammierung herumgespielt. Hab mich damals vor allem an dieser Seite orientiert: http://www.lowlevel.eu. Hab dann auch versucht ein Betriebssystem zu programmieren, aber im Anbetracht der immensen Arbeit die das beinhaltet, ist da natürlich nicht so viel daraus geworden. Was ich daraus mitgenommen habe, ist ein Grundverständnis zu genau den Fragen die du dir hier gestellt hast. Also eine Vorstellung davon, was ein Betriebsystem so macht und konkret, wie es bei x86 funktioniert. Zum Beispiel auch wie Gerätetreiber, Dateissysteme, die Speicherverwaltung (Stichwort: Paging) und Prozess-Scheduling prinzipiell funktionieren.

Ich denke, dass mir das indirekt geholfen hat, effizienten Code zu schreiben oder einige Threading-Probleme zu verstehen. Ich benutze auch gelegentlich explizit die Speicherverwaltung via VirtualAlloc/mmap. Notwendig ist es aber sicher nicht. Oder in anderen Worten: Diese Dinge kann man auch problembezogen lernen. Wenn dich die Sache aber interessiert, gibt es sicher das ein oder andere was man auch für die "gewöhnliche Anwendungsprogramming" daraus mitnehmen kann.
Benutzeravatar
Krishty
Establishment
Beiträge: 8229
Registriert: 26.02.2009, 11:18
Benutzertext: state is the enemy
Kontaktdaten:

Re: Betriebssysteme

Beitrag von Krishty »

Genau. Was außerdem gern vergessen wird, weil man es nicht mehr wahrnimmt: Scheduling.

Dein Programm muss alle paar Millisekunden unterbrochen werden, damit alles andere laufen kann, was dein System zum Betrieb braucht: Anstehende Tastatur- und Mauseingaben verarbeiten z. B.

Wenn dein Programm ohne OS laufen würde, würde es die CPU monopolisieren und alle anderen Prozesse/Treiber/Dienste würden so lange einfrieren. Die Kiste wäre unbedienbar und würde auf nichts reagieren, sofern du nicht explizit Unterbrechungen überall in dein Programm einbaust.

(Das war unter Windows 3 so, das war kooperativ multi-tasked: Dein Programm musste freiwillig via Aufruf ins Betriebssystem Rechenzeit abgeben, damit andere Programme laufen konnten.)

Auch sowas regelt das OS. Wenn ich in den Task-Manager gucke, habe ich 100 Prozesse und 1.500 Threads, und das Betriebssystem regelt, dass alle kurz Rechenzeit bekommen, wenn sie sie brauchen. Sonst könnte ich hier weder lesen noch tippen.
seziert Ace Combat, Driver, und S.T.A.L.K.E.R.   —   rendert Sterne
VirtualLabs2000
Beiträge: 15
Registriert: 26.02.2002, 10:34
Kontaktdaten:

Re: Betriebssysteme

Beitrag von VirtualLabs2000 »

Aber was passiert denn eigentlich wenn ich ein Programm in C oder C++ schreibe, dieses kompiliere und ausführe? Sind das denn nun Instruktionen für die Hardware (übersetzt in 0 und 1) oder sind das tatsächlich nur Befehle für das Betriebssystem?
Zuerstmal lädt das BS dein C/C++ Programm in den Speicher. Dabei kümmert es sich darum, dass für den Code und die Daten deines Programms überhaupt Arbeitsspeicher bereitsteht. Es weist Programm + Daten Stellen im Arbeitsspeicher zu und stellt dabei automatisch sicher, dass diese Stelle im Speicher nicht zufällig auch von einem anderen Programm benutzt wird. Allokiert dein Programm später mit malloc/new mehr Speicher, dann kümmert sich das Betriebssystem darum, dass auch dieser neue Speicherbereich zur Verfügung gestellt wird und nur von deinem Programm benutzt wird.
Weiterhin kümmert sich das BS um das Multitasking. BS + CPU arbeiten zusammen, um dein Programm immer wieder kurz zu unterbrechen und dann weiterlaufen zu lassen. Während dieser kurzen Unterbrechungen kümmert sich die CPU um ganz andere Programme, hat deren Werte in seinen Registern. Aber in dem Moment, wo der Scheduler des BS entschieden hat, dass dein Programm jetzt wieder an der Reihe ist, wird es fortgesetzt und merkt noch nichtmal was davon, dass es eben kurz unterbrochen war.
Wenn dein Programm nach der kurzen Unterbrechung wieder weiterläuft, kann es sein, dass in der Zwischenzeit der ihm zugewiesene Speicher vom RAM auf die Festplatte geschrieben werden musste, weil der RAM voll war und die anderen Programme ihn benötigten. Aber in dem Moment, wo dein Programm das nächste Mal z.B. auf eine Variable oder ein Array zugreifen will, merkt die CPU, dass dieser Speicherbereich gerade nicht im RAM ist, dein Programm wird wieder kurz unterbrochen (Interrupt), die CPU ruft die Speicherverwaltung vom BS auf und diese stellt den Speicherinhalt deines Programms im RAM wieder her (und verschiebt dafür vielleicht die Inhalte anderer Programme auf die Festplatte) und lässt dann dein Programm weiterlaufen. Dein Programm liest/schreibt in seinem Speicher und merkt gar nicht, dass es eben wieder kurz unterbrochen wurde oder dass der Speicherbereich eben kurz mal "weg" war.

Bis zu diesem Punkt meiner Beschreibung bestand dein Programm lediglich aus einfachen Sprunganweisungen, Schleifen, mathematischen Instruktionen und Lese/Schreiboperationen auf Speicherbereiche (Variablen) - Und trotzdem hat das BS hier schon enorm viel im Hintergrund beigetragen.

Jetzt will dein Programm zum ersten Mal ein Zeichen auf den Bildschirm schreiben. printf / cout. Dass da ein Fenster bereitgestellt wird, in das diese Ausgabe dargestellt wird, das macht das BS. Dass sich dieses Fenster verschieben und minimieren lässt, das macht das BS. Das BS stellt deinem Programm das Konsolenfenster bereit und der Befehl zur Textausgabe ruft im Hintergrund Funktionen des BS auf, die sich darum kümmern, dass der Text in der Konsole erscheint.
Als nächstes will dein Programm vielleicht eine Eingabe von der Tastatur lesen. Aber moderne BS erlauben User-Programmen keinen direkten Zugriff auf die Hardware mehr, weil sonst ein Programm leicht den ganzen PC zum Abstürzen bringen könnte und andere Programme beeinflussen könnte. Es ist alles abstrahiert und gekapselt. Dein Programm ruft scanf / cin auf und diese rufen über die Standardbibliothek die Funktionen des BS auf, um die aktuellen Tastatureingaben zu lesen. scanf gibt dir jetzt zurück, dass das Zeichen 'A' eingegeben wurde. Du weißt aber nicht, ob das Zeichen wirklich über die physische Tastatur eingegeben wurde oder vielleicht über die per Maus/Touch bedienbare Bildschirmtastatur oder ob es von einem anderen Programm erzeugt wurde. Um all diese Möglichkeiten kümmert sich das BS und schickt das 'A' über die Standardbibliothek an dein Programm.

Es geht weiter, dein Programm möchte seine Berechnungsergebnisse in einer Datei speichern. Du rufst in C/C++ die Befehle zum Öffnen der Datei mit Schreibzugriff auf, schreibst die Daten hinein und schließt die Datei wieder. Einfach, oder?
Hier beginnt das BS im Hintergrund jetzt richtig zu arbeiten. Denn Dateien/Dateipfade sind auch bloß nur ein abstraktes Konstrukt des BS und seinem Dateisystem, um die Milliarden an Bytes einer Festplatte irgendwie sinnvoll zu strukturieren.
Das BS prüft erstmal, wohin der Dateipfad überhaupt zeigt, den du da gerade öffnen willst. Auf der lokalen Festplatte? Oder vielleicht auf einem anderen Rechner im Netzwerk? Im letzteren Fall stellt es eine Verbindung zu diesem Rechner her, im ersteren Fall muss es "nur" auf die eigene Festplatte zugreifen. Nun prüft es, ob du als Nutzer und dein Programm, was du gerade ausführst, überhaupt die nötigen Berechtigungen habt, um an der gewünschten Stelle eine Datei zu erzeugen. Oder festzustellen, dass es dort schon eine Datei gibt und zu prüfen, ob du + dein Programm sie überschreiben dürft.
Während dein Programm die Datei zum Schreiben geöffnet hat, kümmert sich das BS automatisch darum, dass in der Zwischenzeit kein anderes Programm etwas in diese Datei schreibt. Und wenn dann dein Programm den Schreibvorgang beendet und die Datei schließt, räumt das BS auf -> eventuell automatisch gecachte Schreibbefehle tatsächlich physisch in die Datei = auf den Datenträger schreiben, Zeitstempel für "Letzte Bearbeitung" im Dateisystem für die Datei aktualisieren und zu guter letzt ggf. noch anderen Programmen Bescheid geben, dass die Datei gerade verändert wurde (z.B. einem Virenscanner).

Du merkst, dieser Text ist jetzt schon sehr lang, das BS hat schon enorm viel im Hintergrund geregelt aber dein kleines C/C++ Programm hat eigentlich noch gar nicht viel gemacht.
Threading, Netzwerk, Fenstermanager, Grafik, Benutzerverwaltung etc. waren noch gar nicht im Spiel.

Ja, streng genommen ist das BS auch nur ein Programm. Ein sehr spezielles Programm mit sehr speziellen Aufgaben, das sich darum kümmert, dass andere "normale" Programme sich um sehr vieles von der darunterliegenden Hardware nicht kümmern brauchen/dürfen, sondern einfach ablaufen können.

Ich denke, man MUSS das nicht zwingend alles wissen und verstehen, um Spiele zu programmieren. Zumindest nicht als Anfänger. Aber ich bin überzeugt, dass es auch nicht schadet. Ganz im Gegenteil: Wer solches Wissen lernt, lernt implizit auch sehr viel über Abstraktion und Softwarearchitektur. Wer sich immer mal wieder mit solchen Konzepten auseinandersetzt und sie verstehen lernt, lernt dabei ganz automatisch auch, wie man seine eigenen Programme gut in Komponenten und Schichten aufbauen kann. Oder wie man bestimmte Dinge effizient erledigt. Oder wie man manche Sachen sauber abstrahiert. Oder wie man Sicherheitskonzepte umsetzen sollte.
Benutzeravatar
starcow
Establishment
Beiträge: 523
Registriert: 23.04.2003, 17:42
Echter Name: Mischa Schaub
Kontaktdaten:

Re: Betriebssysteme

Beitrag von starcow »

Wow! Wirklich sehr sehr gut und verständlich zusammengefasst! Ich danke euch vielmals! Das hat jetzt eben meinen Blick aufs Ganze sehr erweitert. Top (-:

Gruss, starcow
Freelancer 3D- und 2D-Grafik
mischaschaub.com
Benutzeravatar
starcow
Establishment
Beiträge: 523
Registriert: 23.04.2003, 17:42
Echter Name: Mischa Schaub
Kontaktdaten:

Re: Betriebssysteme

Beitrag von starcow »

Nach diesen Erklärungen drängt sich bei mir folgende Frage auf:

Woher weiss denn das BS, ob es nun ein Konsolenfenster beim Programmstart öffnen soll? Im Programmcode selbst steckt ja diese Information offenbar nicht mitdrin.
Meine Programme z.B. öffnen die Windowskonsole mit. Aber viele Programme tun das ja nicht...

LG, starcow
Freelancer 3D- und 2D-Grafik
mischaschaub.com
Benutzeravatar
xq
Establishment
Beiträge: 1581
Registriert: 07.10.2012, 14:56
Alter Benutzername: MasterQ32
Echter Name: Felix Queißner
Wohnort: Stuttgart & Region
Kontaktdaten:

Re: Betriebssysteme

Beitrag von xq »

Woher weiss denn das BS, ob es nun ein Konsolenfenster beim Programmstart öffnen soll? Im Programmcode selbst steckt ja diese Information offenbar nicht mitdrin.
Ein Linux weiß das nicht, das öffnet dir einfach die Executable und dann passieren Dinge.

Unter Windows gibt es Subsysteme, die definieren, ob die Anwendung eine Windows-Anwendung oder eine Konsolen-Anwendung ist. Das ist aber Windows-spezifisch
War mal MasterQ32, findet den Namen aber mittlerweile ziemlich albern…

Programmiert viel in ⚡️Zig⚡️ und nervt Leute damit.
Benutzeravatar
Schrompf
Moderator
Beiträge: 4838
Registriert: 25.02.2009, 23:44
Benutzertext: Lernt nur selten dazu
Echter Name: Thomas Ziegenhagen
Wohnort: Dresden
Kontaktdaten:

Re: Betriebssysteme

Beitrag von Schrompf »

Das kompiliert Visual Studio für Dich rein. Wenn Du SubSystem Windows nimmst, kriegst Du beim Starten einfach nur nen Prozess und dann kann's losgehen. Mit ein paar Zeilen kannst Du da aber auch selbst ne Konsole aufmachen, wenn Du eine brauchst. Ne XBox zum Beispiel.
Früher mal Dreamworlds. Früher mal Open Asset Import Library. Heutzutage nur noch so rumwursteln.
Benutzeravatar
starcow
Establishment
Beiträge: 523
Registriert: 23.04.2003, 17:42
Echter Name: Mischa Schaub
Kontaktdaten:

Re: Betriebssysteme

Beitrag von starcow »

xq hat geschrieben: 04.03.2021, 13:32 Ein Linux weiß das nicht, das öffnet dir einfach die Executable und dann passieren Dinge.
Schrompf hat geschrieben: 04.03.2021, 14:06 Das kompiliert Visual Studio für Dich rein. Wenn Du SubSystem Windows nimmst, kriegst Du beim Starten einfach nur nen Prozess und dann kann's losgehen. Mit ein paar Zeilen kannst Du da aber auch selbst ne Konsole aufmachen, wenn Du eine brauchst. Ne XBox zum Beispiel.
Ok!
Und wenn ich dann "nur" einen solchen Prozess habe, landen dann meine cout oder printf Befehle einfach im Nirvana? :->
Freelancer 3D- und 2D-Grafik
mischaschaub.com
Benutzeravatar
Schrompf
Moderator
Beiträge: 4838
Registriert: 25.02.2009, 23:44
Benutzertext: Lernt nur selten dazu
Echter Name: Thomas Ziegenhagen
Wohnort: Dresden
Kontaktdaten:

Re: Betriebssysteme

Beitrag von Schrompf »

starcow hat geschrieben: 04.03.2021, 14:56 Und wenn ich dann "nur" einen solchen Prozess habe, landen dann meine cout oder printf Befehle einfach im Nirvana? :->
Genau. Bis Du von Hand eine Konsole aufmachst und die Streams darauf umleitest.

Das ist bei Linux ja auch nix Anderes, wenn Du dort ein Programm über eine der Grafischen Oberflächen startest.
Früher mal Dreamworlds. Früher mal Open Asset Import Library. Heutzutage nur noch so rumwursteln.
Benutzeravatar
Krishty
Establishment
Beiträge: 8229
Registriert: 26.02.2009, 11:18
Benutzertext: state is the enemy
Kontaktdaten:

Re: Betriebssysteme

Beitrag von Krishty »

Schrompf hat geschrieben: 04.03.2021, 15:13
starcow hat geschrieben: 04.03.2021, 14:56 Und wenn ich dann "nur" einen solchen Prozess habe, landen dann meine cout oder printf Befehle einfach im Nirvana? :->
Genau. Bis Du von Hand eine Konsole aufmachst und die Streams darauf umleitest.
*klugscheiß* Ein Prozess darf auch stdout/stderr haben, ohne eine Konsole zu haben. Z. B. zum Schreiben der Ausgaben in Dateien oder Pipes.

Fun fact: wenn ihr einige Spiele von Konsole aus startet statt via Doppelklick, seht ihr Debug-Ausgaben, die vergessen wurden.
seziert Ace Combat, Driver, und S.T.A.L.K.E.R.   —   rendert Sterne
Antworten