Betriebssystemkonzepte und APUE sagen
Mit vfork () wird der übergeordnete Prozess angehalten und der untergeordnete Prozess verwendet den Adressraum des übergeordneten Prozesses. Da vfork () Copy-on-Write nicht verwendet, werden die geänderten Seiten für den übergeordneten Prozess sichtbar, sobald der untergeordnete Prozess Seiten des Adressraums des übergeordneten Elements ändert, sobald er fortgesetzt wird. Daher muss vfork () mit Vorsicht verwendet werden, um sicherzustellen, dass der untergeordnete Prozess den Adressraum des übergeordneten Prozesses nicht ändert.
vfork () soll verwendet werden, wenn der untergeordnete Prozess unmittelbar nach der Erstellung exec () oder exit () aufruft.
Wie soll ich den letzten Satz verstehen?
Wenn ein untergeordneter Prozess, der durch vfork()
Aufrufe erstellt wurde exec()
, exec()
den Adressraum des übergeordneten Prozesses nicht durch Laden des neuen Programms ändert ?
Wenn ein untergeordneter Prozess, der durch vfork()
Aufrufe erstellt wurde exit()
, exit()
den Adressraum des übergeordneten Prozesses beim Beenden des untergeordneten Prozesses nicht ändert?
Ich bevorzuge Linux.
Vielen Dank.
posix_spawn
. Es ist erheblich schwieriger, korrekten Codeposix_spawn
mit einfachem zu schreiben, als mit einfachem altem Code.fork
Wenn Sie es versuchen, stoßen Sie möglicherweise auf die Mauer, dass es keine Dateiaktion oder kein Attribut gibt, das das tut, was Sie zwischenfork
und tun müssenexec
. Und es ist nicht garantiert, dass es eine vfork-ähnliche Effizienz hat, so dass es nicht einmal das Problem löst, das die Leute wollen, dass es löst.posix_spawn
Ihnen möglicherweise die gewünschte Funktionalität fehlt (Sie können dies über ein zwischengeschaltetes Hilfsprogramm lösen, das in C oder einem Inline-on-cmdline-Shell-Skript geschrieben ist),vfork
ruft jeder Versuch, das zu erreichen, was Sie wollen, gefährliches undefiniertes Verhalten hervor. Die Spezifikation fürvfork
erlaubt es nicht, zufällige Funktionen aufzurufen, um den Status festzulegen, den das Kind zuvor erben sollexecve
, und Versuche, dies zu tun, können den Status des Elternteils beschädigen.posix_spawn
ungefähr genauso wievfork
unter den meisten Bedingungen. Diejenigen, bei denen es einen Unterschied gibt, sind in der Regel genau die Fälle, in denen diesvfork
sehr unsicher ist: Hier sind Signalhandler installiert,posix_spawn
die verhindern müssen, dass das Kind vor der Ausführung ausgeführt wird.Wenn Sie aufrufen
vfork()
, wird ein neuer Prozess erstellt, und dieser neue Prozess leiht das Prozessabbild des übergeordneten Prozesses mit Ausnahme des Stapels aus. Der untergeordnete Prozess erhält einen eigenen neuen Stapelstern, lässt jedoch diereturn
aufgerufene Funktion nicht zuvfork()
.Während das untergeordnete Element ausgeführt wird, wird der übergeordnete Prozess blockiert, da das untergeordnete Element den Adressraum des übergeordneten Elements ausgeliehen hat.
Unabhängig davon, was Sie tun, ändert alles, was nur auf den Stapel zugreift, nur den privaten Stapel des Kindes. Wenn Sie jedoch globale Daten ändern, ändert dies die allgemeinen Daten und wirkt sich somit auch auf die übergeordneten Daten aus.
Dinge, die globale Daten ändern, sind z.
Aufruf von malloc () oder free ()
mit stdio
Ändern der Signaleinstellungen
Ändern von Variablen, die nicht lokal für die aufgerufene Funktion sind
vfork()
....
Sobald Sie anrufen
_exit()
(wichtig, nie anrufenexit()
), wird das Kind beendet und die Kontrolle an das Elternteil zurückgegeben.Wenn Sie eine Funktion aus der
exec*()
Familie aufrufen , wird ein neuer Adressraum mit neuem Programmcode, neuen Daten und einem Teil des Stapels vom übergeordneten Element erstellt (siehe unten). Sobald dies fertig ist, leiht das Kind den Adressraum nicht mehr vom Kind aus, sondern verwendet einen eigenen Adressraum.Das Steuerelement wird an das übergeordnete Element zurückgegeben, da der Adressraum nicht mehr von einem anderen Prozess verwendet wird.
Wichtig: Unter Linux gibt es keine echte
vfork()
Implementierung. Linux implementiert ehervfork()
basierend auf demfork()
1988 von SunOS-4.0 eingeführten Copy on Write- Konzept. Damit Benutzer glauben, dass sie es verwendenvfork()
, richtet Linux nur gemeinsam genutzte Daten ein und setzt das übergeordnete Element aus, während das untergeordnete Element_exit()
oder eine derexec*()
Funktionen nicht aufgerufen hat .Linux profitiert daher nicht von der Tatsache, dass ein Real
vfork()
keine Adressraumbeschreibung für das Kind im Kernel einrichten muss. Dies führt zu einemvfork()
, der nicht schneller als istfork()
. Auf Systemen, die ein reales System implementierenvfork()
, ist es in der Regel dreimal schneller alsfork()
und beeinflusst die Leistung von Shells, dievfork()
-ksh93
, die neuestenBourne Shell
undcsh
.Der Grund, warum Sie niemals
exit()
vomvfork()
ed-Kind anrufen sollten, ist, dassexit()
stdio gelöscht wird, falls Daten aus der Zeit vor dem Anruf nicht gelöscht werdenvfork()
. Dies kann zu seltsamen Ergebnissen führen.Übrigens:
posix_spawn()
wird zusätzlich implementiertvfork()
und wird dahervfork()
nicht aus dem Betriebssystem entfernt. Es wurde erwähnt, dass Linux nichtvfork()
für verwendetposix_spawn()
.Für den Stack gibt es nur wenige Dokumentationen. In der Solaris-Manpage heißt es Folgendes:
Die Implementierung kann also tun, was sie will. Die Solaris-Implementierung verwendet gemeinsam genutzten Speicher für den Stapelrahmen des Funktionsaufrufs
vfork()
. Keine Implementierung gewährt dem übergeordneten Element Zugriff auf ältere Teile des Stapels.quelle
posix_spawn()
auf Linux implementiertvfork()
. Beide implementieren es zusätzlich__clone()
.vfork()
ruft einfachclone()
richtig an? Es ist buchstäblich ein Einzeiler im Kernel.vfork
undfork
unter Linux feststellt, stimmt etwas nicht.