fork() y árbol binario

Dado un programa en la llamada al sistema fork() .

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

¿Cuántos procesos se generarán después de ejecutar el programa anterior?

Una llamada al sistema fork() genera procesos como hojas de un árbol binario en crecimiento. Si llamamos a fork() dos veces, generará 2 2 = 4 procesos. Todos estos 4 procesos forman los hijos hoja del árbol binario. En general, si estamos en el nivel l y fork() se llama incondicionalmente, tendremos 2 l procesos en el nivel ( l+1 ). Es equivalente al número máximo de Nodes secundarios en un árbol binario en el nivel ( l+1 ).

Como otro ejemplo, supongamos que hemos invocado la llamada fork() 3 veces incondicionalmente. Podemos representar el proceso generado usando un árbol binario completo con 3 niveles. En el nivel 3, tendremos 2 3 = 8 Nodes secundarios, lo que corresponde al número de procesos en ejecución.

Una nota sobre los operadores lógicos de C/C++:

El operador lógico && tiene más precedencia que ||, y tiene asociatividad de izquierda a derecha. Después de ejecutar el operando izquierdo, se estimará el resultado final y la ejecución del operando derecho depende del resultado del operando izquierdo, así como del tipo de operación.

En el caso de AND (&&), después de la evaluación del operando izquierdo, el operando derecho se evaluará solo si el operando izquierdo se evalúa como distinto de cero . En el caso de OR (||), después de la evaluación del operando izquierdo, el operando derecho se evaluará solo si el operando izquierdo se evalúa como cero .

Valor de retorno de fork():

Las páginas del manual de fork() citan el siguiente extracto sobre el valor de retorno,

En caso de éxito, el PID del proceso hijo se devuelve en el padre y 0 en el hijo. En caso de falla, se devuelve -1 en el padre, no se crea ningún proceso hijo y errno se establece de manera adecuada.

Un PID es como un identificador de proceso y se representa como int sin firmar . Podemos concluir, el fork() devolverá un valor distinto de cero en padre y cero en hijo. Analicemos el programa. Para facilitar la notación, etiquete cada horquilla() como se muestra a continuación,

#include <stdio.h>
int main()
{
   fork(); /* A */
   ( fork()  /* B */ &&
     fork()  /* C */ ) || /* B and C are grouped according to precedence */
   fork(); /* D */
   fork(); /* E */

   printf("forked\n");
   return 0;
}

El siguiente diagrama proporciona una representación pictórica de la bifurcación de nuevos procesos. Todos los procesos recién creados se propagan en el lado derecho del árbol y los padres se propagan en el lado izquierdo del árbol, en niveles consecutivos.

Las primeras dos llamadas fork() se llaman incondicionalmente.

En el nivel 0, solo tenemos el proceso principal. El principal (m en el diagrama) creará el hijo C1 y ambos continuarán la ejecución. Los niños están numerados en orden creciente de su creación.

En el nivel 1, tenemos m y C1 ejecutándose, y listos para ejecutar fork() – B. (Tenga en cuenta que B, C y D se nombran como operandos de los operadores && y ||). La expresión inicial B se ejecutará en todos los procesos secundarios y primarios que se ejecuten en este nivel.

En el nivel 2, debido a fork() – B ejecutado por m y C1, tenemos m y C1 como padres y C2 y C3 como hijos.

El valor de retorno de fork() – B es distinto de cero en padre y cero en hijo. Dado que el primer operador es &&, debido al valor de retorno cero, los elementos secundarios C2 y C3  no ejecutarán la siguiente expresión (fork()-C). Los procesos padres m y C1 continuarán con fork() – C. Los hijos C2 y C3 ejecutarán directamente fork() – D, para evaluar el valor de la operación lógica OR.

En el nivel 3, tenemos m, C1, C2, C3 como procesos en ejecución y C4, C5 como hijos. La expresión ahora se simplifica a ((B && C) || D), y en este punto el valor de (B && C) es obvio. En los padres es distinto de cero y en los niños es cero. Por lo tanto, los padres conocen el resultado de B && C general || D, omitirá la ejecución de fork() – D. Ya que, en los hijos (B && C) evaluados a cero, ejecutarán fork() – D. Debemos notar que los hijos C2 y C3 creados en el nivel 2, también ejecutar fork() – D como se mencionó anteriormente.

En el nivel 4, tendremos m, C1, C2, C3, C4, C5 como procesos en ejecución y C6, C7, C8 y C9 como procesos secundarios. Todos estos procesos ejecutan incondicionalmente fork() – E, y generan un hijo.

En el nivel 5, tendremos 20 procesos en ejecución. El programa (en Ubuntu Maverick, GCC 4.4.5) se imprimió «bifurcado» 20 veces. Una vez por padre raíz (principal) y el resto por hijos. En general, se generarán 19 procesos.

Una nota sobre el orden de evaluación:

No se especifica el orden de evaluación de las expresiones en operadores binarios. Para obtener más información, lea la publicación  Orden de evaluación de los operandos . Sin embargo, los operadores lógicos son una excepción. Están garantizados para evaluar de izquierda a derecha.

Aportado por  Venki . Escriba comentarios si encuentra algo incorrecto o si desea compartir más información sobre el tema tratado anteriormente.

Publicación traducida automáticamente

Artículo escrito por GeeksforGeeks-1 y traducido por Barcelona Geeks. The original can be accessed here. Licence: CCBY-SA

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *