Wie geht Copy-on-Write in fork () mit mehreren Forks um?

23

Laut Wikipedia (was falsch sein könnte)

Bei einem Systemaufruf von fork () wird eine Kopie aller Seiten erstellt, die dem übergeordneten Prozess entsprechen, und vom Betriebssystem für den untergeordneten Prozess in einen separaten Speicherort geladen. In bestimmten Fällen ist dies jedoch nicht erforderlich. Betrachten Sie den Fall, dass ein Kind einen " exec" Systemaufruf ausführt (mit dem eine ausführbare Datei in einem C - Programm ausgeführt wird) oder sehr bald nach dem beendet wird fork(). Wenn das untergeordnete Element nur zum Ausführen eines Befehls für den übergeordneten Prozess benötigt wird, müssen die Seiten des übergeordneten Prozesses nicht kopiert werden, da execder Adressraum des aufgerufenen Prozesses durch den auszuführenden Befehl ersetzt wird.

In solchen Fällen wird eine Technik verwendet, die als Copy-on-Write (COW) bezeichnet wird. Bei dieser Technik werden beim Verzweigen die Seiten des übergeordneten Prozesses nicht für den untergeordneten Prozess kopiert. Stattdessen werden die Seiten zwischen dem untergeordneten und dem übergeordneten Prozess geteilt. Wenn ein Prozess (übergeordnet oder untergeordnet) eine Seite ändert, wird nur eine separate Kopie dieser bestimmten Seite für den Prozess (übergeordnet oder untergeordnet) erstellt, der die Änderung durchgeführt hat. Bei diesem Vorgang wird in allen zukünftigen Verweisen die neu kopierte Seite anstelle der freigegebenen Seite verwendet. Der andere Prozess (der die freigegebene Seite nicht geändert hat) verwendet weiterhin die Originalkopie der Seite (die jetzt nicht mehr freigegeben ist). Diese Technik wird als Copy-on-Write bezeichnet, da die Seite kopiert wird, wenn ein Prozess darauf schreibt.

Es scheint, dass, wenn einer der Prozesse versucht, auf die Seite zu schreiben, eine neue Kopie der Seite zugewiesen und dem Prozess zugewiesen wird, der den Seitenfehler erzeugt hat. Die Originalseite wird anschließend als beschreibbar markiert.

Meine Frage ist: Was passiert, wenn die fork()mehrmals aufgerufen wird, bevor einer der Prozesse versucht, auf eine freigegebene Seite zu schreiben?

ssgao
quelle
Wikipedia ist in diesem Fall richtig, nur höherwertiger.
Didi Kohen
1
Ja, Copy-on-Write ist ein fauler Kopiervorgang. Ein untergeordneter Prozess kopiert die Seite, wenn versucht wird, sie zu schreiben. Nach einer Abzweigung wird also das Gedächtnis eines Kindes fast mit dem eines Elternteils geteilt. Vor jedem der durchgeführten Prozesse verfügt jeder untergeordnete Prozess jedoch noch über einen privaten Speicher, der von den übergeordneten oder neuen Zuordnungen geändert wurde. Das bedeutet, dass der Forked-Child-Prozess auch ohne Aktion einen privaten Speicher hat. Wir können es mit pmap -XX PIDoder überprüfen cat /proc/PID/smap.
wo23
Betreff: "Die Originalseite wird danach als beschreibbar markiert." Wem gehört sie? Hier der andere Prozess, der nicht versucht hat, es zu schreiben?
Adil
Das ist schön. Lassen Sie uns dies in Kindergärten unterrichten
22.

Antworten:

18

Es passiert nichts Besonderes. Alle Prozesse teilen sich die gleichen Seiten und jeder erhält eine eigene private Kopie, wenn er eine Seite ändern möchte.

jlliagre
quelle
Recht. Der Punkt ist, es ist der untergeordnete Prozess, der speziell ist und den Kopierauftrag hat, wenn er versucht, auf die freigegebene Seite zu schreiben. Weder die Eltern noch die anderen Kinder müssen über die Änderung Bescheid wissen, wenn sie korrekt durchgeführt wird.
Charles Stewart
9
Der Kindprozess ist nicht so besonders. Sowohl der untergeordnete als auch der übergeordnete Prozess verfügen nach der Verzweigung über denselben Satz schreibgeschützter Seiten. Für diese Seiten ist die Seitenbehandlung symmetrisch.
Juli
3

Das Verhalten von fork () hängt davon ab, ob das * nix-System eine MMU hat oder nicht. Auf einem Nicht-MMU-System (wie frühen PDP-11-Systemen) hat der Systemaufruf fork () den gesamten Arbeitsspeicher der Eltern für jedes Kind kopiert. Auf einem MMU-basierten * nix-System markiert der Kernel alle nicht gestapelten Seiten als R / O und teilt sie zwischen übergeordneten und untergeordneten Seiten. Wenn dann einer der beiden Prozesse auf eine Seite schreibt, fängt die MMU den Versuch ab, der Kernel weist dann eine beschreibbare Seite zu und aktualisiert die MMU-Seitentabellen so, dass sie auf die jetzt beschreibbare Seite verweisen. Dieses Verhalten beim Kopieren beim Schreiben sorgt für eine Beschleunigung, da anfangs nur ein privater Stapel für jeden untergeordneten Prozess zugewiesen und geklont werden muss.

Wenn Sie zwischen den Aufrufen von fork () übergeordneten Code ausführen, unterscheiden sich die resultierenden untergeordneten Prozesse von den Seiten, die vom übergeordneten Code geändert wurden. Wenn das übergeordnete Element hingegen einfach mehrere fork () - Aufrufe ausgibt, z. B. in einer Schleife, sind die untergeordneten Prozesse nahezu identisch. Wenn eine lokale Schleifenvariable verwendet wird, ist dies innerhalb des Stapels jedes Kindes unterschiedlich.

CyberFonic
quelle
0

Wenn das System eine Verzweigung durchführt (dies kann von der Implementierung abhängen), werden die Seiten normalerweise auch als schreibgeschützt und der übergeordnete Prozess als Master dieser Seiten gekennzeichnet.
Beim Versuch, auf diese Seiten zu schreiben, tritt ein Seitenfehler auf, und das Betriebssystem übernimmt das Kopieren der gesamten Liste der Seiten oder nur der geänderten Seiten (wiederum abhängig von der Implementierung), sodass für den Schreibvorgang eine beschreibbare Kopie erstellt wird.
Wenn es mehrere Prozesse gibt, die aus demselben Prozess hervorgehen, und der "Master" -Prozess in seinen Speicher schreibt, werden für die anderen Prozesse die entsprechenden Seiten kopiert.

Didi Kohen
quelle
Welches System macht das? Linux verwendet eine Copy-on-Write-Implementierung
brauliobo 10.10.14
So funktioniert das Copy-on-Write ...
Didi Kohen
3
@DavidKohen So funktioniert Copy-on-Write in keiner Version, von der ich jemals gehört habe. Es gibt keinen "Master" -Prozess. Wenn ein einzelner Prozess die freigegebenen Seiten schreibt, wird seine Kopie an eine private gestoßen, während alle anderen Prozesse sie weiterhin freigeben.
Celada
1
Ich denke, David Kohen hat irgendwann Recht. Dies ist eine Möglichkeit, Copy-on-Write zu implementieren. Das Wesentliche wäre, dass mit dieser Markierung das Schreiben auf diese Seite einen Seitenfehler-Handler auslösen würde, der dann geeignete Maßnahmen ergreift, dh das Kopieren beim Schreiben. Leider ist dieses Detail (das systemspezifisch wäre) für die Frage meistens irrelevant. Denken Sie daran, dass CoW zwei Dimensionen hat: eine, die für den Prozess sichtbar ist, und eine, wie der Kernel sie implementieren könnte.
0xC0000022L