Warum druckt dieses Programm "gegabelt!" 4 Mal?
#include <stdio.h>
#include <unistd.h>
int main(void) {
fork() && (fork() || fork());
printf("forked!\n");
return 0;
}
Warum druckt dieses Programm "gegabelt!" 4 Mal?
#include <stdio.h>
#include <unistd.h>
int main(void) {
fork() && (fork() || fork());
printf("forked!\n");
return 0;
}
Antworten:
Der erste fork()
gibt einen Wert ungleich Null im aufrufenden Prozess zurück (nennen Sie es p0) und 0 im untergeordneten Prozess (nennen Sie es p1).
In p1 wird der Kurzschluss für &&
genommen und der Prozess wird aufgerufen printf
und beendet. In p0 muss der Prozess den Rest des Ausdrucks auswerten. Dann wird fork()
erneut aufgerufen, wodurch ein neuer untergeordneter Prozess erstellt wird (p2).
In p0 wird fork()
ein Wert ungleich Null zurückgegeben, und der Kurzschluss für ||
wird genommen, sodass der Prozess aufgerufen printf
und beendet wird.
In p2 wird fork()
0 zurückgegeben, also der Rest von || muss ausgewertet werden, welches das letzte ist fork()
; das führt zur Erstellung eines Kindes für p2 (nenne es p3).
P2 wird dann ausgeführt printf
und beendet.
P3 wird dann ausgeführt printf
und beendet.
printf
Dann werden 4 s ausgeführt.
&&
Null ist, die anderen Operanden nicht ausgewertet werden. Wenn ein Operand von a nach der gleichen Logik ||
1 ist, müssen die restlichen Operanden nicht ausgewertet werden. Dies liegt daran, dass die restlichen Operanden das Ergebnis des logischen Ausdrucks nicht ändern können und daher nicht ausgeführt werden müssen. Dadurch sparen wir Zeit. Besser jetzt rona? Gute Frage übrigens, ich kann nicht verstehen, warum die Abstimmungen. Du hast meine +1.
fork()
, aber ich weiß nicht einmal, was Kurzschluss ist. War das eine Frage in der Schule?
Der eine kommt von main()
und die anderen drei von jedem fork()
.
Beachten Sie, dass alle drei forks()
ausgeführt werden. Vielleicht möchten Sie einen Blick auf die Referenz werfen :
RÜCKGABEWERT
Nach erfolgreichem Abschluss gibt fork () 0 an den untergeordneten Prozess zurück und gibt die Prozess-ID des untergeordneten Prozesses an den übergeordneten Prozess zurück . Beide Prozesse müssen weiterhin über die Funktion fork () ausgeführt werden. Andernfalls wird -1 an den übergeordneten Prozess zurückgegeben, es wird kein untergeordneter Prozess erstellt, und errno wird festgelegt, um den Fehler anzuzeigen.
Beachten Sie, dass die Prozess-ID nicht Null sein kann, wie hier angegeben .
Was passiert also wirklich?
Wir haben:
fork() && (fork() || fork());
Der erste fork()
gibt also seine Prozess-ID ungleich Null an den übergeordneten Prozess zurück, während er 0 an den untergeordneten Prozess zurückgibt. Dies 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 fork()
s nicht aufruft .
Jetzt wissen wir also, dass wir mindestens zwei Drucke erhalten werden (einen vom Haupt- und einen vom 1. fork()
).
Jetzt wird die zweite fork()
im übergeordneten Prozess ausgeführt, und es wird ein Wert ungleich Null an den übergeordneten Prozess und eine Null im untergeordneten Prozess zurückgegeben.
Daher setzt das übergeordnete Element die Ausführung nicht bis zum letzten fort fork()
(aufgrund eines Kurzschlusses), während der untergeordnete Prozess die letzte Verzweigung ausführt, da der erste Operand von ||
0 ist.
Das bedeutet also, dass wir zwei weitere Abzüge erhalten.
Als Ergebnis erhalten wir insgesamt vier Abzüge.
Kurzschluss
Hier Kurzschlüsse im Grunde bedeutet , dass , wenn der erste Operand von && Null ist , dann wird der andere Operand (en) ist / sind nicht ausgewertet. Nach der gleichen Logik, wenn ein Operand von a || ist 1, dann müssen die restlichen Operanden nicht ausgewertet werden. Dies geschieht, weil der Rest der Operanden das Ergebnis des logischen Ausdrucks nicht ändern kann und sie daher nicht ausgeführt werden müssen, sodass wir Zeit sparen.
Siehe Beispiel unten.
Prozess
Denken Sie daran, dass ein übergeordneter Prozess Nachkommenprozesse erstellt, die wiederum andere Prozesse usw. erstellen. Dies führt zu einer Hierarchie von Prozessen (oder einem Baum, den man sagen könnte).
Vor diesem Hintergrund lohnt es sich, sich dieses ähnliche Problem sowie diese Antwort anzuschauen .
Beschreibendes Bild
Ich habe auch diese Figur gemacht, die helfen kann, denke ich. Ich nahm an, dass die zurückgegebenen PIDs fork()
3, 4 und 5 für jeden Anruf sind.
Beachten Sie, dass einige fork()
s ein rotes X über sich haben, was bedeutet, dass sie aufgrund der Kurzschlussauswertung des logischen Ausdrucks nicht ausgeführt werden.
Die fork()
s oben werden nicht ausgeführt, da der erste Operand des Operators &&
0 ist. Daher führt der gesamte Ausdruck zu 0, sodass die Ausführung des Restes der Operanden von &&
.
Das fork()
untere wird nicht ausgeführt, da es der zweite Operand von a ist ||
, wobei sein erster Operand eine Zahl ungleich Null ist. Daher wird das Ergebnis des Ausdrucks bereits als wahr ausgewertet, unabhängig davon, was der zweite Operand ist.
Und im nächsten Bild sehen Sie die Hierarchie der Prozesse: basierend auf der vorherigen Abbildung.
Beispiel für einen 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
Für alle Downvoter ist dies eine zusammengeführte, aber andere 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 Bediener sind kurzgeschlossen, daher erhalten Sie Folgendes:
fork()
/ \
0/ \>0
|| fork() && fork()
/\ / \
/ \ 0/ \>0
* * || fork() *
/ \
* *
Das sind also insgesamt 4 * 5 = 20 Prozesse, bei denen jeweils eine Zeile gedruckt wird.
Hinweis: Wenn fork () aus irgendeinem Grund fehlschlägt (z. B. wenn Sie die Anzahl der Prozesse begrenzt haben), wird -1 zurückgegeben, und Sie können unterschiedliche Ergebnisse erhalten.
fork() && fork() || fork();
, während die hier verwendete Frage verwendet wird fork() && (fork() || fork());
. Es gab eine Zusammenführung, wie hier beschrieben: " meta.stackoverflow.com/questions/281729/… ". Möglicherweise möchten Sie Ihre Antwort bearbeiten und zukünftige Leser benachrichtigen.
Ausführen fork() && (fork() || fork())
, was passiert
Jeder fork
gibt 2 Prozesse mit den Werten pid (Eltern) und 0 (Kind).
Erste Gabel:
&& (fork() || fork())
||
Teils => printforked
|| fork()
forked
forked
forked
Gesamt: 4 forked
Ich mag alle Antworten, die bereits eingereicht wurden. Wenn Sie Ihrer printf-Anweisung ein paar weitere Variablen hinzufügen, können Sie möglicherweise leichter sehen, 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 hat es diese Ausgabe erzeugt:
forked! PID=3694 Child = 0
forked! PID=3696 Child = 0
forked! PID=3693 Child = 1
forked! PID=3695 Child = 1
long f1,f2,f3; (f1 = fork()) && ((f2 = fork()) || (f3 = fork()));
und drucken Sie dann die PID und die drei Einzelwerte aus.
Dieser Code:
fork();
fork() && fork() || fork();
fork();
Erhält 20 Prozesse für sich und 20 Mal wird Printf gehen.
Und für
fork() && fork() || fork();
printf wird insgesamt 5 mal gehen.
fork() && fork() || fork();
, während die hier verwendete Frage verwendet wird fork() && (fork() || fork());
. Es gab eine Zusammenführung, wie hier beschrieben: " meta.stackoverflow.com/questions/281729/… ". Möglicherweise möchten Sie Ihre Antwort bearbeiten und zukünftige Leser benachrichtigen.