Warum gibt dieses Programm „forked!“ aus? 4 Mal?
#include <stdio.h>
#include <unistd.h>
int main(void) {
fork() && (fork() || fork());
printf("forked!\n");
return 0;
}
Rawan Lezzeik
Warum gibt dieses Programm „forked!“ aus? 4 Mal?
#include <stdio.h>
#include <unistd.h>
int main(void) {
fork() && (fork() || fork());
printf("forked!\n");
return 0;
}
Gsamaras
Der eine kommt von main()
und die anderen drei von jedem fork()
.
Beachten Sie, dass alle drei forks()
werden hingerichtet. Vielleicht möchten Sie einen Blick auf die werfen Ref:
RÜCKGABEWERT
Nach erfolgreichem Abschluss fork() soll 0 an den untergeordneten Prozess zurückgeben und soll die Prozess-ID des untergeordneten Prozesses an den übergeordneten Prozess zurückgeben. Beide Prozesse sollen weiterhin von der Funktion fork() ausgeführt werden. Andernfalls wird -1 an den übergeordneten Prozess zurückgegeben, kein untergeordneter Prozess erstellt und errno zur Anzeige des Fehlers gesetzt.
Beachten Sie, dass die Prozess-ID, wie angegeben, nicht Null sein kann hier.
Was passiert also wirklich?
Wir haben:
fork() && (fork() || fork());
Also das erste fork()
gibt dem Elternprozess seine Nicht-Null-Prozess-ID zurück, während er 0 an den Kindprozess zurückgibt. Das bedeutet, dass die erste Verzweigung des logischen Ausdrucks im übergeordneten Prozess als wahr ausgewertet wird, während sie im untergeordneten Prozess als falsch ausgewertet wird und aufgrund der Kurzschlussauswertung die verbleibenden zwei nicht aufruft fork()
s.
Jetzt wissen wir also, dass wir mindestens zwei Drucke bekommen werden (einen vom Haupt- und einen vom 1 fork()
).
Nun, der 2 fork()
im übergeordneten Prozess ausgeführt werden soll, tut dies und gibt einen Wert ungleich null an den übergeordneten Prozess und einen Wert von null im untergeordneten Prozess zurück.
Jetzt wird der Elternteil die Ausführung nicht bis zum letzten fortsetzen fork()
(aufgrund von Kurzschlüssen), während der untergeordnete Prozess die letzte Verzweigung seit dem ersten Operanden von ausführt ||
ist 0.
Das bedeutet also, dass wir zwei weitere Drucke bekommen werden.
Als Ergebnis erhalten wir insgesamt vier Drucke.
Kurzschluss
Hier, Kurzschluss bedeutet im Grunde, dass wenn der erste Operand von && Null ist, der/die andere(n) Operand(en) nicht ausgewertet wird/werden. Nach der gleichen Logik, wenn ein Operand eines || 1 ist, müssen die restlichen Operanden nicht ausgewertet werden. Dies geschieht, weil die restlichen Operanden das Ergebnis des logischen Ausdrucks nicht ändern können, also nicht ausgeführt werden müssen, wodurch wir Zeit sparen.
Siehe Beispiel unten.
Verfahren
Denken Sie daran, dass ein übergeordneter Prozess untergeordnete Prozesse erstellt, die wiederum andere Prozesse erstellen und so weiter. Dies führt zu einer Hierarchie von Prozessen (oder einem Baum könnte man sagen).
Vor diesem Hintergrund lohnt es sich, sich dieses ähnliche Problem sowie diese Antwort anzusehen.
Beschreibendes Bild
Ich habe auch diese Figur gemacht, die helfen kann, denke ich. Ich nahm an, dass die PID fork()
zurückgegeben werden 3, 4 und 5 für jeden Anruf.
Beachten Sie, dass einige fork()
s haben ein rotes X darüber, was bedeutet, dass sie wegen der kurzschließenden Auswertung des logischen Ausdrucks nicht ausgeführt werden.
Das fork()
s ganz oben werden nicht ausgeführt, da der erste Operand des Operators &&
ist 0, daher wird der gesamte Ausdruck zu 0 führen, also ist es nicht wesentlich, den Rest der Operanden von auszuführen &&
.
Das fork()
ganz unten wird nicht ausgeführt, da es der zweite Operand von a ist ||
wobei der erste Operand eine Zahl ungleich Null ist, sodass das Ergebnis des Ausdrucks bereits als wahr ausgewertet wird, unabhängig davon, was der zweite Operand ist.
Und im nächsten Bild sieht man die Hierarchie der Prozesse:
basierend auf der vorherigen Abbildung.
Beispiel für Kurzschluss
#include <stdio.h>
int main(void) {
if(printf("A printf() results in logic true\n"))
;//empty body
if(0 && printf("Short circuiting will not let me execute\n"))
;
else if(0 || printf("I have to be executed\n"))
;
else if(1 || printf("No need for me to get executed\n"))
;
else
printf("The answer wasn't nonsense after all!\n");
return 0;
}
Ausgabe:
A printf() results in logic true
I have to be executed
Jean-Baptiste Yunes
Der Erste fork()
gibt im aufrufenden Prozess einen Wert ungleich Null zurück (nennen Sie es p0) und 0 im untergeordneten Prozess (nennen Sie es p1).
In p1 der Kurzschluss für &&
genommen wird und der Prozess aufruft printf
und beendet. In p0 muss der Prozess den Rest des Ausdrucks auswerten. Dann ruft es fork()
erneut, wodurch ein neuer untergeordneter Prozess (p2) erstellt wird.
In p0 fork()
gibt einen Wert ungleich Null zurück, und der Kurzschluss für ||
genommen wird, also ruft der Prozess auf printf
und beendet.
In p2, fork()
gibt 0 zurück, also den Rest von || muss ausgewertet werden, das ist das letzte fork()
; das führt zur Erstellung eines untergeordneten Elements für p2 (nennen Sie es p3).
P2 wird dann ausgeführt printf
und beendet.
P3 wird dann ausgeführt printf
und beendet.
4 printf
s werden dann ausgeführt.
könnten Sie bitte erklären “Kurzschluss für && wird genommen”?
– Rawan Lezzeik
3. November 2014 um 15:04 Uhr
@rona-altico, überprüfe den Link zum Kurzschluss in meiner Antwort. Es bedeutet im Grunde, dass wenn der erste Operand von &&
Null ist, dann werden die anderen Operanden nicht ausgewertet. Auf der gleichen Logik, wenn ein Operand von a ||
1 ist, dann müssen die restlichen Operanden nicht ausgewertet werden. Dies geschieht, weil die Rest-Operanden das Ergebnis des logischen Ausdrucks nicht ändern können und daher nicht ausgeführt werden müssen, wodurch wir Zeit sparen. Besser jetzt Rona? Nette Frage übrigens, ich kann nicht verstehen, warum die Ablehnungen. Sie haben meine +1 bekommen.
– Gsamaras
3. November 2014 um 15:09 Uhr
@rona-altico: Es fällt mir schwer zu verstehen, warum Sie verwenden möchten fork()
, aber nicht einmal wissen, was Kurzschluss ist. War das eine Frage in der Schule?
– Sebastian Mach
4. November 2014 um 11:55 Uhr
@G.Samaras: Ich schätze, es wird abgelehnt, weil es eines von vielen Duplikaten ist, und zeigt keine Mühe, es zu googeln, bevor Sie hier fragen.
– chr
4. November 2014 um 12:45 Uhr
@G.Samaras: Sie können nicht sehen, warum die Ablehnungen? Das ist ein abscheulich Frage. Es gibt ein exaktes Duplikat und er hat sich nicht die Mühe gemacht zu erklären, welche unterschiedliche Ausgabe er erwartet hat. Warum dies 41 positive Stimmen hat, ist mir völlig schleierhaft; normalerweise erreicht so etwas schnell -3 oder -4.
– Leichtigkeitsrennen im Orbit
6. November 2014 um 17:24 Uhr
Karl Horvath
Für alle Downvoter stammt dies aus einer zusammengeführten, aber anderen Frage. Schuld SO. Vielen Dank.
Sie können das Problem in drei Zeilen zerlegen, die erste und die letzte Zeile verdoppeln einfach die Anzahl der Prozesse.
fork() && fork() || fork();
Die Operatoren schließen kurz, also erhalten Sie Folgendes:
fork()
/ \
0/ \>0
|| fork() && fork()
/\ / \
/ \ 0/ \>0
* * || fork() *
/ \
* *
Das sind also insgesamt 4 * 5 = 20 Prozesse, die jeweils eine Zeile drucken.
Hinweis: Wenn fork() aus irgendeinem Grund fehlschlägt (z. B. wenn die Anzahl der Prozesse begrenzt ist), gibt es -1 zurück und Sie können dann andere Ergebnisse erhalten.
Danke @yi_H für deine Antwort und eine Sache, wenn nur diese Zeile in unserem Code vorhanden wäre, dann wäre die Ausgabe 5-mal gegabelt??
– Amit Singh Tomar
17. August 2011 um 11:29 Uhr
Und auch fork1() || Gabel2() && Gabel3(); Diese Anweisung führt zu 16 Prozessen.
– Amit Singh Tomar
17. August 2011 um 11:34 Uhr
Hi @yi_H bin nur verwirrt, wie “fork1() || fork2() && fork3()” insgesamt 16 ergibt. Ich meine, kann ich ein Diagramm wie dieses haben, das Sie oben erwähnt haben?
– Amit Singh Tomar
25. Oktober 2011 um 8:58 Uhr
Ohne Klammern analysieren Sie den logischen Baum möglicherweise falsch. Führt der falsche (0) Pfad von der ersten fork() nicht dazu, dass der gesamte Ausdruck am && kurzgeschlossen wird? ich denken die Assoziativitätspriorität von && und || in C sind von rechts nach links, so dass eine einfache Auswertung von links nach rechts den Rest des Unterausdrucks kurzschließen kann (innerhalb von Klammern). Es ist dasselbe wie fork() && (fork() || fork()) Dies würde dann die 4 (nicht 5) Prozesse aus dieser Zeile allein und 16 insgesamt erklären. Es mag in C++ oder C# anders sein, aber diese Frage war in C.
– Rob Parker
4. November 2014 um 0:03 Uhr
Dies beantwortet die Frage, die verwendet fork() && fork() || fork();
während die Frage hier verwendet fork() && (fork() || fork());
. Es gab eine Zusammenführung, wie hier besprochen: “meta.stackoverflow.com/questions/281729/…”. Möglicherweise möchten Sie Ihre Antwort bearbeiten und zukünftige Leser benachrichtigen.
– Gsamaras
5. Januar 2015 um 18:14 Uhr
Ausführen fork() && (fork() || fork())
was geschieht
Jeder fork
gibt 2 Prozesse mit den jeweiligen Werten pid (Eltern) und 0 (Kind)
Erste Gabel:
&& (fork() || fork())
||
Teil => drucken forked
|| fork()
forked
forked
forked
Insgesamt: 4 forked
Ich mag alle Antworten, die bereits eingereicht wurden. Wenn Sie Ihrer printf-Anweisung ein paar weitere Variablen hinzufügen, können Sie vielleicht leichter erkennen, was passiert.
#include<stdio.h>
#include<unistd.h>
int main(){
long child = fork() && (fork() || fork());
printf("forked! PID=%ld Child=%ld\n", getpid(), child);
return 0;
}
Auf meiner Maschine erzeugte es diese Ausgabe:
forked! PID=3694 Child = 0
forked! PID=3696 Child = 0
forked! PID=3693 Child = 1
forked! PID=3695 Child = 1
Was ist mit den Werten, die von jedem Aufruf von fork() zurückgegeben werden? Wie wäre es mit: long f1,f2,f3; (f1 = fork()) && ((f2 = fork()) || (f3 = fork()));
und dann die PID und die drei Einzelwerte drucken.
– Rob Parker
4. November 2014 um 0:10 Uhr
Peter Mortensen
Dieser Code:
fork();
fork() && fork() || fork();
fork();
bekommt 20 Prozesse für sich und 20 mal wird Printf gehen.
Und für
fork() && fork() || fork();
printf wird insgesamt 5 Mal ausgeführt.
Was ist mit den Werten, die von jedem Aufruf von fork() zurückgegeben werden? Wie wäre es mit: long f1,f2,f3; (f1 = fork()) && ((f2 = fork()) || (f3 = fork()));
und dann die PID und die drei Einzelwerte drucken.
– Rob Parker
4. November 2014 um 0:10 Uhr