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 die return
aufgerufene Funktion nicht zu vfork()
.
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 anrufen exit()
), 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 eher vfork()
basierend auf dem fork()
1988 von SunOS-4.0 eingeführten Copy on Write- Konzept. Damit Benutzer glauben, dass sie es verwenden vfork()
, richtet Linux nur gemeinsam genutzte Daten ein und setzt das übergeordnete Element aus, während das untergeordnete Element _exit()
oder eine der exec*()
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 einem vfork()
, der nicht schneller als ist fork()
. Auf Systemen, die ein reales System implementieren vfork()
, ist es in der Regel dreimal schneller als fork()
und beeinflusst die Leistung von Shells, die vfork()
- ksh93
, die neuesten Bourne Shell
und csh
.
Der Grund, warum Sie niemals exit()
vom vfork()
ed-Kind anrufen sollten, ist, dass exit()
stdio gelöscht wird, falls Daten aus der Zeit vor dem Anruf nicht gelöscht werden vfork()
. Dies kann zu seltsamen Ergebnissen führen.
Übrigens: posix_spawn()
wird zusätzlich implementiert vfork()
und wird daher vfork()
nicht aus dem Betriebssystem entfernt. Es wurde erwähnt, dass Linux nicht vfork()
für verwendet posix_spawn()
.
Für den Stack gibt es nur wenige Dokumentationen. In der Solaris-Manpage heißt es Folgendes:
The vfork() and vforkx() functions can normally be used the
same way as fork() and forkx(), respectively. The calling
procedure, however, should not return while running in the
child's context, since the eventual return from vfork() or
vforkx() in the parent would be to a stack frame that no
longer exists.
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.