sentencia - do while
Visualmente, ¿qué le sucede a tenedor() en un bucle For (3)
He estado tratando de entender el comportamiento fork()
. Esta vez en un for-loop
. Observe el siguiente código:
#include <stdio.h>
void main()
{
int i;
for (i=0;i<3;i++)
{
fork();
// This printf statement is for debugging purposes
// getppid(): gets the parent process-id
// getpid(): get child process-id
printf("[%d] [%d] i=%d/n", getppid(), getpid(), i);
}
printf("[%d] [%d] hi/n", getppid(), getpid());
}
Aquí está el resultado:
[6909][6936] i=0
[6909][6936] i=1
[6936][6938] i=1
[6909][6936] i=2
[6909][6936] hi
[6936][6938] i=2
[6936][6938] hi
[6938][6940] i=2
[6938][6940] hi
[1][6937] i=0
[1][6939] i=2
[1][6939] hi
[1][6937] i=1
[6937][6941] i=1
[1][6937] i=2
[1][6937] hi
[6937][6941] i=2
[6937][6941] hi
[6937][6942] i=2
[6937][6942] hi
[1][6943] i=2
[1][6943] hi
Soy una persona muy visual y, por lo tanto, la única manera de que yo entienda verdaderamente las cosas es haciendo un diagrama. Mi instructor dijo que habría 8 declaraciones. Escribí y ejecuté el código, y de hecho hubo 8 declaraciones. Pero realmente no lo entendí Entonces dibujé el siguiente diagrama:
Diagrama actualizado para reflejar los comentarios :)
Observaciones:
- El proceso principal (principal) debe iterar el ciclo 3 veces. Luego se llama printf
- En cada iteración de parent for-loop se llama fork ()
- Después de cada llamada fork (), i se incrementa, por lo que cada hijo inicia un for-loop desde i antes de que se incremente
- Al final de cada for-loop, se imprime "hola"
Aquí están mis preguntas:
- ¿Mi diagrama es correcto?
- ¿Por qué hay dos instancias de
i=0
en la salida? - ¿Qué valor de
i
se transfiere a cada niño después de la horquilla ()? Si se transfiere el mismo valor dei
, ¿cuándo se detiene el "bifurcación"? - ¿Es siempre el caso que
2^n - 1
sería una forma de contar la cantidad de niños bifurcados? Entonces, aquín=3
, lo que significa2^3 - 1 = 8 - 1 = 7
hijos, ¿cuál es el correcto?
- Sí, es correcto. (vea abajo)
- No,
i++
se ejecuta después de la llamada delfork
, porque esa es la formafor
funciona el buclefor
. - Si todo va bien, sí. Sin embargo, recuerda que el
fork
puede fallar.
Una pequeña explicación sobre la segunda:
for (i = 0;i < 3; i++)
{
fork();
}
es parecido a:
i = 0;
while (i < 3)
{
fork();
i++;
}
Entonces, en los procesos bifurcados (padre e hijo) es el valor antes del incremento. Sin embargo, el incremento se ejecuta inmediatamente después de fork()
, por lo que en mi opinión, el diagrama podría tratarse como correcto.
Aquí se explica cómo entenderlo, comenzando en el ciclo for
.
El bucle comienza en el padre,
i == 0
Parent
fork()
s, creando el hijo 1.Ahora tiene dos procesos. Ambos imprimen
i=0
.Loop se reinicia en ambos procesos, ahora
i == 1
.fork()
padre e hijo 1fork()
, creando hijos 2 y 3.Ahora tiene cuatro procesos. Los cuatro imprimen
i=1
.Loop se reinicia en los cuatro procesos, ahora
i == 2
.Padres e hijos de 1 a 3 todos
fork()
, creando niños de 4 a 7.Ahora tiene ocho procesos. Los ocho imprimen
i=2
.Loop se reinicia en los ocho procesos, ahora
i == 3
.Loop termina en los ocho procesos, ya que
i < 3
ya no es verdadero.Los ocho procesos imprimen
hi
.Los ocho procesos terminan.
Por lo tanto, se obtiene 0
impreso dos veces, 1
impreso cuatro veces, 2
impreso 8 veces y hi
impreso 8 veces.
Para responder a sus preguntas una por una:
¿Mi diagrama es correcto?
Sí, esencialmente. Es un diagrama muy bueno también.
Es decir, es correcto si interpreta las etiquetas i=0
etc. como referencias a iteraciones de bucle completo. Lo que el diagrama no muestra, sin embargo, es que, después de cada fork()
, la parte de la iteración del bucle actual después de la llamada fork()
también se ejecuta mediante el proceso hijo bifurcado.
¿Por qué hay dos instancias de
i=0
en la salida?
Porque tiene el printf()
después de la fork()
, así que se ejecuta tanto por el proceso principal como por el proceso hijo recién bifurcado. Si mueve el printf()
antes de la fork()
, solo lo ejecutará el padre (ya que el proceso hijo aún no existe).
¿Qué valor de
i
se transfiere a cada niño después de lafork()
? Si se transfiere el mismo valor dei
, ¿cuándo se detiene el "bifurcación"?
El valor de i
no es modificado por fork()
, por lo que el proceso hijo ve el mismo valor que su padre.
Lo que hay que recordar sobre fork()
es que se llama una vez, pero vuelve dos veces, una vez en el proceso principal y otra vez en el proceso recién clonado.
Para un ejemplo más simple, considere el siguiente código:
printf("This will be printed once./n");
fork();
printf("This will be printed twice./n");
fork();
printf("This will be printed four times./n");
fork();
printf("This will be printed eight times./n");
El proceso hijo creado por fork()
es un clon (casi) exacto de su elemento principal y, por lo tanto, desde su propio punto de vista, "recuerda" que es el padre, heredando todo el estado del proceso padre (incluidos todos los valores variables, la llamada pila y la instrucción que se está ejecutando). La única diferencia inmediata (aparte de los metadatos del sistema como la ID del proceso devuelta por getpid()
) es el valor de retorno de fork()
, que será cero en el proceso secundario pero distinto de cero (en realidad, la ID del proceso secundario) ) en el padre.
¿Es siempre el caso que
2^n - 1
sería una forma de contar la cantidad de niños bifurcados? Entonces, aquín=3
, lo que significa2^3 - 1 = 8 - 1 = 7
hijos, ¿cuál es el correcto?
Cada proceso que ejecuta una fork()
convierte en dos procesos (excepto en condiciones de error inusuales, donde fork()
puede fallar). Si el padre y el hijo siguen ejecutando el mismo código (es decir, no verifican el valor de retorno de fork()
, o su propio ID de proceso, y se ramifican a diferentes rutas de código en función de él), cada bifurcación posterior duplicará el número de procesos. Entonces, sí, después de tres bifurcaciones, terminarás con 2³ = 8 procesos en total.