syscall pid_t how example c linux unix fork systems-programming

pid_t - ¿Por qué este programa imprime "bifurcado" 4 veces?



vfork (6)

¿Por qué este programa imprime "bifurcado" 4 veces?

#include <stdio.h> #include <unistd.h> int main(void) { fork() && (fork() || fork()); printf("forked!/n"); return 0; }


Ejecutando fork() && (fork() || fork()) , qué sucede

Cada fork proporciona 2 procesos con valores respectivamente pid (padre) y 0 (hijo)

Primer tenedor:

  • el valor de retorno primario es pid no nulo => ejecuta el && (fork() || fork())
    • el segundo valor primario de la bifurcación es pid no nulo deja de ejecutar el || parte => impresión forked
    • valor secundario del segundo tenedor = 0 => ejecuta el || fork() || fork()
      • impresiones horquilla del tercer tenedor forked
      • tercer tenedor infantil estampados forked
  • el valor de retorno secundario es 0, deja de ejecutar && part => impresiones forked

Total: 4 forked


El primer fork() devuelve un valor distinto de cero en el proceso de llamada (llámelo p0) y 0 en el hijo (llámelo p1).

En p1 se toma el cortocircuito para && y el proceso llama a printf y finaliza. En p0 el proceso debe evaluar el resto de la expresión. Luego llama a fork() nuevamente, creando así un nuevo proceso hijo (p2).

En p0 fork() devuelve un valor distinto de cero, y el cortocircuito para || se toma, por lo que el proceso llama a printf y finaliza.

En p2, fork() devuelve 0, por lo que el resto de || debe evaluarse, que es la última fork() ; eso lleva a la creación de un hijo para p2 (llámelo p3).

P2 luego ejecuta printf y termina.

P3 luego ejecuta printf y termina.

Se ejecutan 4 printf s.


El primero proviene de main() y los otros tres de cada fork() .

Observe que los tres forks() se ejecutarán. Es posible que desee echar un vistazo a la ref :

VALOR DEVUELTO

Al completar con éxito, fork () devolverá 0 al proceso hijo y devolverá la ID del proceso hijo al proceso padre . Ambos procesos continuarán ejecutándose desde la función fork (). De lo contrario, -1 se devolverá al proceso padre, no se creará ningún proceso hijo y se establecerá errno para indicar el error.

Tenga en cuenta que la identificación del proceso no puede ser cero, como se indica here .

Entonces, ¿qué pasa realmente?

Tenemos:

fork() && (fork() || fork());

Por lo tanto, el primer fork() devolverá al padre su id. De proceso distinto de cero, mientras que devolverá 0 al proceso hijo. Eso significa que la primera bifurcación de la expresión lógica se evaluará como verdadera en el proceso primario, mientras que en el proceso secundario se evaluará como falsa y, debido a la evaluación de Cortocircuito , no llamará a las dos fork() restantes fork() .

Entonces, ahora sabemos que obtendremos al menos dos impresiones (una de main y otra de la primera fork() ).

Ahora, la segunda fork() en el proceso padre se ejecutará, lo hace y devuelve un valor distinto de cero al proceso padre y cero en el proceso hijo.

Así que ahora, el padre no continuará la ejecución hasta la última fork() (debido a cortocircuito), mientras que el proceso secundario ejecutará la última bifurcación, desde el primer operando de || es 0.

Eso significa que obtendremos dos impresiones más.

Como resultado, obtenemos cuatro impresiones en total.

Cortocircuito

Aquí, el cortocircuito básicamente significa que si el primer operando de && es cero, entonces los otros operandos no son evaluados. En la misma lógica, si un operando de a || es 1, entonces el resto de los operandos no necesitan evaluación. Esto sucede porque el resto de los operandos no pueden cambiar el resultado de la expresión lógica, por lo que no es necesario ejecutarlos, por lo que ahorramos tiempo.

Ver ejemplo a continuación.

Proceso

Recuerde que un proceso padre crea procesos descendientes que a su vez crean otros procesos, etc. Esto lleva a una jerarquía de procesos (o un árbol que se podría decir).

Teniendo esto en cuenta, vale la pena echar un vistazo a este problema similar , así como a this respuesta.

Imagen descriptiva

También hice esta figura que puede ayudar, supongo. Supuse que la fork() pid fork() devuelta son 3, 4 y 5 por cada llamada.

Observe que algunos fork() s tienen una X roja sobre ellos, lo que significa que no se ejecutan debido a la evaluación de cortocircuito de la expresión lógica.

Los fork() s en la parte superior no se ejecutarán, ya que el primer operando del operador && es 0, por lo tanto, la expresión completa dará como resultado 0, por lo que no hay esencia en la ejecución del resto de los operandos de && .

La fork() en la parte inferior no se ejecutará, ya que es el segundo operando de un || , donde su primer operando es un número distinto de cero, por lo tanto, el resultado de la expresión ya se evalúa como verdadero, sin importar cuál sea el segundo operando.

Y en la siguiente imagen puedes ver la jerarquía de los procesos: basado en la figura anterior.

Ejemplo de cortocircuito

#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; }

Salida:

A printf() results in logic true I have to be executed


Este código:

fork(); fork() && fork() || fork(); fork();

obtiene 20 procesos por sí mismo y 20 veces Printf irá.

Y para

fork() && fork() || fork();

printf irá un total de 5 veces.


Me gustan todas las respuestas que ya se han enviado. Quizás si agrega algunas variables más a su declaración printf, le sería más fácil ver lo que está sucediendo.

#include<stdio.h> #include<unistd.h> int main(){ long child = fork() && (fork() || fork()); printf("forked! PID=%ld Child=%ld/n", getpid(), child); return 0; }

En mi máquina produjo esta salida:

forked! PID=3694 Child = 0 forked! PID=3696 Child = 0 forked! PID=3693 Child = 1 forked! PID=3695 Child = 1


Para todos los votantes negativos, esto se debe a una pregunta combinada pero diferente. Culpa a SO. Gracias.

Puede descomponer el problema en tres líneas, la primera y la última línea simplemente duplican el número de procesos.

fork() && fork() || fork();

Los operadores están en corto circuito, así que esto es lo que obtienes:

fork() / / 0/ />0 || fork() && fork() // / / / / 0/ />0 * * || fork() * / / * *

Esto es en total 4 * 5 = 20 procesos cada impresión de una línea.

Nota: Si por alguna razón fork () falla (por ejemplo, tiene algún límite en el número de procesos), devuelve -1 y luego puede obtener resultados diferentes.