Frage von JamesOffice, 41

Welche Systemaufrufe machen UNIX zu einem Multitasking-BS (d.h sind dafür verantwortlich, dass mehrere Prozesse "gleichzeitig" auf einem Rechner laufen können)?

wie Oben bereits erwähnt weiß ich nicht welche Systemaufrufe UNIX zu einem Multitasking-BS machen! Sind das fork() und excec() ? Wie lauten Sie unter MS Windows CreateProcesse? Könnte mir jemand bitte das erklären :) vielen Dank!

Hilfreichste Antwort - ausgezeichnet vom Fragesteller
von kloogshizer, 31

Für die "gleichzeitige" Ausführung von Prozessen ist der Scheduler zuständig. Der ist selbst kein Prozess, sondern Teil des Kernels, und ist dafür zuständig, Hard- und Softwarekontext beim Prozesswechsel rein- und rauszuladen (damit pausierte Prozesse später die Befehlsausführung auf der CPU fortsetzen können), und den Prozessen CPU-Zeit zuzuweisen.

Systemcalls werden soweit ich weiß nur von Prozessen getätigt. 

Kommentar von JamesOffice ,

Genau! Sie werden ja von Prozessen getätigt. Aber wie ich gestern gelesen habe, gibt es ja 2 Systeme Aufrufe (Anscheinend User-Mode-->Kernel-Mode) die UNIX zu einem Multitasking BS machen! bloß finde ich fork(), excec() oder system() irgendwie unlogisch aber was wären dann diese 2 Aufrufe?!
Danke!

Kommentar von kloogshizer ,

Die Ausführung eines Prozesses ist unter jedem Betriebssystem möglich, ein Singletask-BS welches keine Möglichkeit vorsieht eine Anwendung zu starten wäre ja irgendwie sinnlos. So denk ich mir das jedenfalls.

fork() ist aber definitiv etwas was nur in Multitasking-BS zu finden ist.

Antwort
von TeeTier, 9

Systemaufrufe (= Syscalls) werden im Userspace oder auch im Kernelspace getätigt, ABER nur im Kernelspace ausgeführt!

Ein Userspace-Prozess bittet also den Kernel darum, etwas zu tun. Die Ausführung springt also zwischen User- und Kernelspace hin- und her. Diese sog. Kontextwechsel sind eine relativ teure und ressourcenfressende Angelegenheit. Sollte man - wenn möglich - vermeiden.

Du kannst aber auch reines Userspace-Multithreading implementieren, indem du selbst einen Scheduler zur Verfügung stellst. Durch die fehlenden Kontextwechsel sind diese oft extrem effizient. (Ich denke, z. B. Erlang hat diese perfektioniert und bietet die wohl besten User-Threads auf diesem Gebiet an.)

Zurück zum Thema: Wenn dein Programm fork() aufruft, bittet es einfach nur den Kernel darum etwas zu tun ... nämlich den aktuellen Prozess zu kopieren, anzupassen, zu initialisieren, zu starten, und noch eine Million interne Dinge mehr.

Wenn der Kernel damit fertig ist, trägt den neuen Prozess in seine Prozess-Tabelle ein, und übergibt den entsprechenden Rücksprungpunkt an den Scheduler.

Wenn jetzt einer der beiden Prozesse an der Reihe ist, wird die Ausführung im Elternprozess fortgesetzt, und im kopierten Kindprozess an dem Punkt gestartet, der direkt hinter fork() liegt.

Die exec()-Familie hat erstmal gar nichts damit zu tun, denn exec() sorgt nur dafür, dass das aktuelle Speicherabbild des Prozesses durch ein neues aus einer Datei ersetzt wird. Dabei werden einige Speicherstrukturen des aufrufenden Prozesses beibehalten, andere hingegen mit Standardwerten initialisiert. (Stichwort Dateideskriptoren, Signalmaske, die ganzen UIDs, GIDs, usw. usf.)

Naja, das ganze ist ein komplexes Thema, und ich erhebe ausdrücklich keinen Anspruch auf Vollständigkeit! Außerdem sind viele meiner obigen Aussagen nicht 100% präzise, und teilweise zu stark vereinfachend, aber ich will hier den Rahmen nicht sprengen.

Ich hoffe, das alles reicht dir erst mal!

Schönen Abend noch! :)

PS: Genau genommen ist fork() nicht mal ein Syscall, sondern nur ein Wrapper für die Laufzeitbibliothek, obwohl es "man 2 fork" gibt, und eine eigene Syscall-Nummer vorhanden ist.

Früher hat man tatsächlich direkt den fork-Syscall benutzt, heutzutage gilt das aber als veraltet. Wenn man sich mal anguckt, was der fork()-Wrapper in der glibc macht, versteht man auch warum! Intern wird mit clone() gearbeitet, womit auch POSIX-Threads erzeugt werden. (Genau genommen ist sogar clone() auch nur ein Wrapper, aber ich lass das mal jetzt.) :)

Kommentar von TeeTier ,

PS: Wenn du nicht gerade einen Demon schreibst, ist wait() bzw. waitpid() oder besser waitid() ebenfalls wichtig, um Zombieprozesse zu verhindern.

Wenn du mit Pipes arbeitest, dann evtl. noch open(), close(), pipe(), dup() oder dup2() oder dup3().

Evtl. noch fcntl().

Aber eigentlich reicht für einfache Multiprozess-Programme fork()-exec()-wait() aus. :)

Hier gibt es ein kurzes Beispiel weiter unten auf der Seite:

http://linux.die.net/man/2/pipe

Das erschöpft aber nicht mal ansatzweise alle Möglichkeiten und ist kein sonderlich sicherer Stil. Behalte im Hinterkopf, dass es nur ein BEISPIEL ist ... mehr nicht! :)

Keine passende Antwort gefunden?

Fragen Sie die Community