fork () verzweigt mehr als erwartet?


Antworten:


245

Das fork()Primitive regt oft die Vorstellungskraft an. Bis Sie ein Gefühl dafür bekommen, sollten Sie auf Papier nachvollziehen, was jeder Vorgang ist, und die Anzahl der Prozesse berücksichtigen. Vergessen Sie nicht, dass fork () eine nahezu perfekte Kopie des aktuellen Prozesses erstellt. Der wichtigste Unterschied (für die meisten Zwecke) besteht darin, dass fork()der Rückgabewert zwischen Eltern und Kind unterschiedlich ist. (Da dieser Code den Rückgabewert ignoriert, macht er keinen Unterschied.)

Zunächst gibt es also einen Prozess. Dadurch wird ein zweiter Prozess erstellt, bei dem beide einen Punkt und eine Schleife drucken. Bei der zweiten Iteration erstellt jeder eine weitere Kopie, sodass vier Prozesse einen Punkt drucken und dann beenden. So können wir problemlos sechs Punkte berücksichtigen, wie Sie es erwarten.

Was jedoch printf()wirklich tut, ist die Ausgabe zu puffern. Der erste Punkt aus der Zeit, als es nur zwei Prozesse gab, wird beim Schreiben nicht angezeigt. Diese Punkte verbleiben im Puffer, der bei fork () dupliziert wird. Erst wenn der Prozess beendet ist, wird der gepufferte Punkt angezeigt. Vier Prozesse drucken einen gepufferten Punkt, und der neue ergibt 8 Punkte.

Wenn Sie dieses Verhalten vermeiden möchten, rufen Sie fflush(stdout);danach an printf().


12
Danke, ich wusste nicht, dass der Puffer mit fork () dupliziert wird. Es erklärt so ein seltsames Verhalten.
Nikolay Kovalenko

1
Sollte das nicht 10 Punkte geben, nicht 8? Da die 4 Kinder der zweiten Generation den gepufferten Punkt erben, ihren eigenen hinzufügen und beim Beenden leeren, würden sie insgesamt 8 Punkte drucken, aber dann würden die 2 Prozesse der ersten Generation immer noch jeweils einen Punkt gepuffert und die beim Beenden leeren. Geben von insgesamt 10.
Psusi

12
@psusi Einer der Prozesse der zweiten Generation ist ein Prozess der ersten Generation. fork()erstellt nicht 2, sondern beendet, sondern nur 1 weiteren Prozess.
Izkata

70

Sie haben nicht festgeschriebene Puffer in den Ausgabestreams . stdout ist zeilengepuffert und der Puffer wird zusammen mit dem Rest des Prozesses repliziert. Wenn das Programm beendet wird, wird der nicht festgeschriebene Puffer zweimal geschrieben (einmal für jeden Prozess). Beide verwenden

printf("a\n");

und

printf("a "); fflush(stdout);

Zeigen Sie das Problem nicht.

In Ihrem ersten Beispiel erstellen Sie vier Prozesse, deren Ausgabestream-Puffer jeweils zwei Punkte enthält. Wenn jeder Stream beendet wird, wird sein Puffer geleert und acht Punkte generiert.


2

wenn i = 0

Prozess_1: Gepufferter Text = 1 Punkt

Process_2 (erstellt von Process_1): Gepufferter Text = 1 Punkt

wenn i = 1

Process_3 (erstellt von Process_1): Erbt 1 gepufferten Punkt von Process_1 und druckt 1 Punkt selbst. Insgesamt druckt Process_3 2 Punkte.

Process_4 (erstellt von Process_2): Erbt 1 gepufferten Punkt von Process_2 und druckt 1 Punkt selbst. Insgesamt druckt Process_4 2 Punkte.

Prozess_1: Druckt 2 Punkte (Ein gepufferter Punkt bei i = 0 und ein weiterer Punkt bei i = 1)

Prozess_2: Druckt 2 Punkte (Ein gepufferter Punkt bei i = 0 und ein weiterer Punkt bei i = 1)

Endgültige Ausgabe: 8 Punkte. :) :)

Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.