linux - solicita - ¿Cómo funcionan 2 o más llamadas al sistema tenedor?
llamada al sistema exec (4)
Aquí hay un código donde uso 2 llamadas al sistema fork () una tras otra: ¿cómo funciona realmente?
#include <unistd.h>
#include <iostream.h>
using namespace std;
int main()
{
cout << "0. I am process " << getpid() << endl;
(void) fork();
cout << "1. I am process " << getpid() << endl;
(void) fork();
cout << "2. I am process " << getpid() << endl;
}
Obtengo el resultado como:
0. Soy el proceso 27701
1. Soy proceso 25915
1. Soy proceso 27701
2. Soy el proceso 27781
2. Yo soy el proceso 26170
2. Soy el proceso 27701
Este es el próximo programa en el que utilicé 3 llamadas al sistema de horquillas, ¿cómo obtengo ese resultado? Si tuviera que resolver este código manualmente, ¿cuál sería la lógica?
#include <unistd.h>
#include <iostream>
using namespace std;
int main()
{
cout << "0. I am process " << getpid() << endl;
(void) fork();
cout << "1. I am process " << getpid() << endl;
(void) fork();
cout << "2. I am process " << getpid() << endl;
(void) fork();
cout << "3. I am process " << getpid() << endl;
}
Aquí obtengo el resultado como:
0. Soy proceso 27116
1. Soy proceso 26147
2. Soy proceso 27371
2. Yo soy el proceso 26147
3. Soy proceso 24416
3. Soy proceso 27371
3. Soy el proceso 27508
3. Soy proceso 26147
1. Soy proceso 27116
2. Soy el proceso 21406
2. Soy proceso 27116
3. Soy proceso 27369
3. Soy el proceso 21406
3. Soy el proceso 26752
3. Soy proceso 27116
Simplemente dibuje un árbol donde cada nodo raíz es una llamada de horquilla y los nodos de hoja son el código que lo sigue.
En el primer programa, su cout << "0 ..." es el programa principal y después de la llamada de la bifurcación, el programa completo después de esa línea se ejecuta dos veces. Por lo tanto, las dos líneas de salida "1 ...".
Ahora hay otra llamada fork después de esto. Esta vez hay 3 procesos en ejecución (1. El padre original que invocó, 2. El hijo que engendró 3. El propio niño engendra a otro nieto).
De ahí las líneas de salida de 3 "2 ...".
Tu programa está completamente equivocado. Nunca debes ignorar el resultado del fork
.
Lea el libro de programación de Linux avanzado y la página de manual de fork (2) (lea esa página varias veces y con cuidado).
El código típico debería ser:
pid_t pid1 = fork();
if (pid1<0) { perror("fork1 failed"); exit(EXIT_FAILURE); }
else if (pid1 == 0) {
// you are in the child process
}
else // pid1>0
{ // you are in the parent process
}
Y del mismo modo para pid_t pid2=fork();
y luego para pid_t pid3=fork();
etc ... Así que cada llamada al fork
debe manejar los 3 casos de resultado de la fork
(falla, por ejemplo, <0
, proceso hijo ==0
, proceso principal >0
)
En principio, tienes 3 3, es decir, 27 posibilidades. Pero podrías manejar el caso de falla temprano, lo que deja 2 3, es decir, 8. posibilidades
No te olvides de manejar la falla de la fork
. Puede reducir el límite de su proceso (con el límite de secuencia (2) usando RLIMIT_NPROC
o el builtin basal ulimit bash) para facilitar la prueba de falla de la fork
.
cuando se llama a un tenedor (), se crea un proceso secundario y se ejecuta. Por lo tanto, obtendrá la siguiente instrucción ejecutada una vez en el proceso hijo:
cout << "1. I am process " << getpid() << endl;
Además, cuando se llama a otro tenedor, se crea otro proceso secundario que ejecuta la siguiente instrucción ''cout''. Sin embargo, el proceso principal también se ejecuta. Esto sucede para la tercera bifurcación () también.
Todo esto tiene lugar en el proceso hijo de la primera bifurcación (). Después de esto, el proceso principal para la primera bifurcación también se ejecuta para mostrar su resultado.
fork()
funciona de la misma manera cada vez que lo llamas. Se crea un nuevo proceso como una copia exacta del proceso actual, y ambos continúan la ejecución como si acabaran de regresar de la llamada a la función fork()
, solo con diferentes valores de retorno. En tu caso, tiras ese valor de retorno, por lo que solo son procesos idénticos.
Hagamos un dibujo para su primer ejemplo. Ejemplo de salida de una ejecución que acabo de realizar (dado que el resultado que ingresó en su pregunta está incompleto):
0. I am process 25597
1. I am process 25597
2. I am process 25597
1. I am process 25598
2. I am process 25599
2. I am process 25598
2. I am process 25600
Comienza con un proceso único con PID 25597. Imprime la línea 0
y luego se bifurca. Eso produce dos procesos:
25597 # prints "0"
//
/ /
/ /
25597 25598 # both print "1"
Hasta aquí todo bien. Ahora ambos de estos nuevos procesos llaman a fork()
nuevamente. El árbol completo termina luciendo así:
25597
//
/ /
/ /
/ /
/ /
25597 25598 # both print "1"
// //
/ / / /
/ / / /
25597 25599 25598 25600 # all four print "2"
Las ubicaciones reales de 25599 y 25600 no pueden adivinarse desde la salida, lamentablemente, también podrían ser al revés.
Para su ejemplo de 3 fork()
, solo tiene que hacer lo mismo, pero tendrá otro nivel en el diagrama: terminará con 8 procesos imprimiendo cada uno la línea "3".