¿Cuál es el propósito de fork ()?

En muchos progtwigs y páginas de manual de Linux, he visto código usando fork() . ¿Por qué necesitamos usar fork() y cuál es su propósito?

fork() es cómo crear nuevos procesos en Unix. Cuando llama a fork , está creando una copia de su propio proceso que tiene su propio espacio de direcciones . Esto permite que múltiples tareas se ejecuten independientemente una de otra, como si cada una tuviera la memoria completa de la máquina.

Aquí hay algunos ejemplos de usos de fork :

  1. Tu shell usa el fork para ejecutar los progtwigs que invocas desde la línea de comando.
  2. Los servidores web como apache usan fork para crear múltiples procesos de servidor, cada uno de los cuales maneja las solicitudes en su propio espacio de direcciones. Si uno muere o pierde la memoria, otros no se ven afectados, por lo que funciona como un mecanismo para la tolerancia a fallas.
  3. Google Chrome usa la fork para manejar cada página dentro de un proceso separado. Esto evitará que el código del lado del cliente en una página desactive todo su navegador.
  4. fork se utiliza para generar procesos en algunos progtwigs paralelos (como los escritos usando MPI ). Tenga en cuenta que esto es diferente al uso de hilos , que no tienen su propio espacio de direcciones y existen dentro de un proceso.
  5. Los lenguajes de scripting usan indirectamente fork para iniciar procesos secundarios. Por ejemplo, cada vez que usa un comando como subprocess.Popen en Python, fork un proceso secundario y lee su salida. Esto permite que los progtwigs trabajen juntos.

El uso típico de un fork en una concha podría verse así:

 int child_process_id = fork(); if (child_process_id) { // Fork returns a valid pid in the parent process. Parent executes this. // wait for the child process to complete waitpid(child_process_id, ...); // omitted extra args for brevity // child process finished! } else { // Fork returns 0 in the child process. Child executes this. // new argv array for the child process const char *argv[] = {"arg1", "arg2", "arg3", NULL}; // now start executing some other program exec("/path/to/a/program", argv); } 

El shell genera un proceso hijo utilizando exec y espera a que se complete, luego continúa con su propia ejecución. Tenga en cuenta que no tiene que usar el tenedor de esta manera. Siempre se pueden generar muchos procesos secundarios, como lo puede hacer un progtwig paralelo, y cada uno puede ejecutar un progtwig simultáneamente. Básicamente, cada vez que creas nuevos procesos en un sistema Unix, estás usando fork() . Para el equivalente de Windows, eche un vistazo a CreateProcess .

Si desea más ejemplos y una explicación más larga, Wikipedia tiene un resumen decente. Y aquí hay algunas diapositivas aquí sobre cómo funcionan los procesos, subprocesos y la concurrencia en los sistemas operativos modernos.

fork () es cómo Unix crea nuevos procesos. En el punto que llamó fork (), su proceso se clona, ​​y dos procesos diferentes continúan la ejecución desde allí. Uno de ellos, el niño, tendrá un retorno de fork () 0. El otro, el padre, tendrá un fork () para devolver el PID (ID de proceso) del niño.

Por ejemplo, si escribe lo siguiente en un shell, el progtwig del shell llamará fork () y luego ejecutará el comando que pasó (telnetd, en este caso) en el hijo, mientras que el padre mostrará el indicador nuevamente. como un mensaje que indica el PID del proceso en segundo plano.

 $ telnetd & 

En cuanto a la razón por la que crea nuevos procesos, así es como su sistema operativo puede hacer muchas cosas al mismo tiempo. Es por eso que puede ejecutar un progtwig y, mientras se está ejecutando, cambiar a otra ventana y hacer otra cosa.

fork () se utiliza para crear proceso hijo. Cuando se llama a una función fork (), se genera un nuevo proceso y la llamada a la función fork () devolverá un valor diferente para el hijo y el padre.

Si el valor de retorno es 0, sabe que es el proceso secundario y si el valor de retorno es un número (que es el id del proceso secundario), sabe que es el padre. (y si es un número negativo, la bifurcación falló y no se creó ningún proceso secundario)

http://www.yolinux.com/TUTORIALS/ForkExecProcesses.html

fork () creará un nuevo proceso hijo idéntico al padre. Por lo tanto, todo lo que ejecute en el código después será ejecutado por ambos procesos, muy útil si tiene, por ejemplo, un servidor y desea manejar múltiples solicitudes.

fork () se usa básicamente para crear un proceso secundario para el proceso en el que está llamando a esta función. Cada vez que llamas a fork (), devuelve un cero para la identificación del niño.

 pid=fork() if pid==0 //this is the child process else if pid!=0 //this is the parent process 

De este modo, puede proporcionar diferentes acciones para el padre y el hijo y hacer uso de la función de subprocesos múltiples.

Es probable que no necesite usar fork en la progtwigción del día a día si está escribiendo aplicaciones.

Incluso si desea que su progtwig inicie otro progtwig para realizar alguna tarea, existen otras interfaces más simples que utilizan la bifurcación entre bastidores, como “sistema” en C y perl.

Por ejemplo, si desea que su aplicación inicie otro progtwig como bc para que realice algún cálculo por usted, puede usar ‘sistema’ para ejecutarlo. El sistema hace un ‘fork’ para crear un nuevo proceso, luego un ‘exec’ para convertir ese proceso en bc. Una vez que bc finaliza, el sistema devuelve el control a su progtwig.

También puede ejecutar otros progtwigs de forma asíncrona, pero no recuerdo cómo.

Si está escribiendo servidores, shells, virus o sistemas operativos, es más probable que desee utilizar fork.

Fork crea nuevos procesos. Sin la bifurcación tendrías un sistema Unix que solo podría ejecutar init.

La llamada al sistema fork () se utiliza para crear procesos. No toma argumentos y devuelve un ID de proceso. El propósito de fork () es crear un nuevo proceso, que se convierte en el proceso secundario de la persona que llama. Después de crear un nuevo proceso hijo, ambos procesos ejecutarán la siguiente instrucción después de la llamada al sistema fork (). Por lo tanto, tenemos que distinguir al padre del niño. Esto se puede hacer probando el valor devuelto de fork ():

Si fork () devuelve un valor negativo, la creación de un proceso hijo no tuvo éxito. fork () devuelve un cero al proceso hijo recién creado. fork () devuelve un valor positivo, el ID de proceso del proceso hijo, al padre. El ID de proceso devuelto es del tipo pid_t definido en sys / types.h. Normalmente, el ID de proceso es un entero. Además, un proceso puede usar la función getpid () para recuperar el ID de proceso asignado a este proceso. Por lo tanto, después de la llamada del sistema a fork (), una prueba simple puede indicar qué proceso es el niño. Tenga en cuenta que Unix hará una copia exacta del espacio de direcciones del padre y se la dará al niño. Por lo tanto, los procesos padre e hijo tienen espacios de direcciones separados.

Entendámoslo con un ejemplo para aclarar los puntos anteriores. Este ejemplo no distingue los procesos padre y hijo.

 #include  #include  #include  #define MAX_COUNT 200 #define BUF_SIZE 100 void main(void) { pid_t pid; int i; char buf[BUF_SIZE]; fork(); pid = getpid(); for (i = 1; i <= MAX_COUNT; i++) { sprintf(buf, "This line is from pid %d, value = %d\n", pid, i); write(1, buf, strlen(buf)); } } 

Supongamos que el progtwig anterior se ejecuta hasta el punto de la llamada a fork ().

Si la llamada a fork () se ejecuta con éxito, Unix hará dos copias idénticas de espacios de direcciones, una para el padre y la otra para el hijo. Ambos procesos comenzarán su ejecución en la siguiente statement después de la llamada a fork (). En este caso, ambos procesos comenzarán su ejecución en la asignación.

 pid = .....; 

Ambos procesos comienzan su ejecución justo después de la llamada al sistema fork (). Dado que ambos procesos tienen espacios de direcciones idénticos pero separados, esas variables que se inicializan antes de la llamada fork () tienen los mismos valores en ambos espacios de direcciones. Dado que cada proceso tiene su propio espacio de direcciones, cualquier modificación será independiente de las demás. En otras palabras, si el padre cambia el valor de su variable, la modificación solo afectará a la variable en el espacio de direcciones del proceso padre. Otros espacios de direcciones creados por llamadas de fork () no se verán afectados aunque tengan nombres de variables idénticos.

¿Cuál es la razón de usar write en lugar de printf? Se debe a que printf () está "almacenado en búfer", lo que significa que printf () agrupará la salida de un proceso. Mientras almacena en búfer la salida para el proceso principal, el niño también puede usar printf para imprimir cierta información, que también se almacenará en búfer. Como resultado, dado que la salida no se enviará a la pantalla inmediatamente, es posible que no obtenga el orden correcto del resultado esperado. Peor aún, la salida de los dos procesos puede mezclarse de formas extrañas. Para superar este problema, puede considerar utilizar la escritura "sin búfer".

Si ejecuta este progtwig, es posible que vea lo siguiente en la pantalla:

 ................ This line is from pid 3456, value 13 This line is from pid 3456, value 14 ................ This line is from pid 3456, value 20 This line is from pid 4617, value 100 This line is from pid 4617, value 101 ................ This line is from pid 3456, value 21 This line is from pid 3456, value 22 ................ 

El ID de proceso 3456 puede ser el asignado al padre o al hijo. Debido al hecho de que estos procesos se ejecutan simultáneamente, sus líneas de salida se entremezclan de una manera bastante impredecible. Además, el orden de estas líneas está determinado por el progtwigdor de la CPU. Por lo tanto, si ejecuta este progtwig nuevamente, puede obtener un resultado totalmente diferente.

El multiprocesamiento es fundamental para la computación. Por ejemplo, su IE o Firefox puede crear un proceso para descargar un archivo para usted mientras todavía navega por Internet. O bien, mientras imprime un documento en un procesador de textos, aún puede mirar diferentes páginas y seguir editando con él.

Fork () se utiliza para crear nuevos procesos como cada cuerpo ha escrito.

Aquí está mi código que crea procesos en forma de árbol binario … Se le pedirá que escanee la cantidad de niveles hasta los que desea crear procesos en el árbol binario.

 #include #include #include int main() { int t1,t2,p,i,n,ab; p=getpid(); printf("enter the number of levels\n");fflush(stdout); scanf("%d",&n); printf("root %d\n",p);fflush(stdout); for(i=1;i 

SALIDA

  enter the number of levels 3 root 20665 child pid 20670 parent pid 20665 child pid 20669 parent pid 20665 child pid 20672 parent pid 20670 child pid 20671 parent pid 20670 child pid 20674 parent pid 20669 child pid 20673 parent pid 20669 

fork() se utiliza para generar un proceso hijo. Normalmente se usa en situaciones similares a las de los hilos, pero hay diferencias. A diferencia de los hilos, fork() crea procesos separados enteros, lo que significa que el hijo y el padre, mientras son copias directas entre sí en el punto en que se llama fork() , están completamente separados, ninguno puede acceder al espacio de memoria del otro ( sin ir a los problemas normales, vas a acceder a la memoria de otro progtwig).

fork() aún es utilizado por algunas aplicaciones de servidor, principalmente las que se ejecutan como root en una máquina * NIX que elimina los permisos antes de procesar las solicitudes de los usuarios. Todavía hay algunos otros casos de uso, pero la mayoría de las personas se han movido ahora a multihilo.

Primero hay que entender qué es la llamada al sistema fork (). Dejame explicar

  1. La llamada al sistema fork () crea el duplicado exacto del proceso principal. Confecciona el duplicado de la stack principal, el montón, los datos inicializados, los datos no inicializados y comparte el código en modo de solo lectura con el proceso principal.

  2. La llamada del sistema de bifurcaciones copia la memoria en la base de copia en escritura, significa que el niño hace en la página de memoria virtual cuando hay un requisito de copia.

Ahora Propósito de tenedor ():

  1. Fork () se puede usar en el lugar donde hay división de trabajo, como lo hace un servidor para manejar múltiples clientes. Por lo tanto, los padres deben aceptar la conexión de manera regular, por lo que el servidor hace fork para que cada cliente realice la lectura y escritura.

Uso de la llamada al sistema de Fork () para crear un proceso hijo. Es el duplicado exacto del proceso padre. Fork copia la sección de la stack, la sección del montón, la sección de datos, la variable de entorno, los argumentos de la línea de comando del padre

Consulte: http://man7.org/linux/man-pages/man2/fork.2.html

La función fork () se utiliza para crear un nuevo proceso duplicando el proceso existente desde el que se llama. El proceso existente desde el que se llama a esta función se convierte en el proceso principal y el proceso recién creado se convierte en el proceso secundario. Como ya se dijo, child es una copia duplicada del padre, pero hay algunas excepciones.

  • El niño tiene un PID único como cualquier otro proceso que se ejecuta en el sistema operativo.

  • El niño tiene un ID de proceso principal que es el mismo que el PID del
    Proceso que lo creó.

  • La utilización de recursos y los contadores de tiempo de CPU se restablecen a cero en el proceso secundario.

  • El conjunto de señales pendientes en el niño está vacío.

  • El hijo no hereda ningún temporizador de su padre

Ejemplo:

  #include  #include  #include  #include  #include  #include  int var_glb; /* A global variable*/ int main(void) { pid_t childPID; int var_lcl = 0; childPID = fork(); if(childPID >= 0) // fork was successful { if(childPID == 0) // child process { var_lcl++; var_glb++; printf("\n Child Process :: var_lcl = [%d], var_glb[%d]\n", var_lcl, var_glb); } else //Parent process { var_lcl = 10; var_glb = 20; printf("\n Parent process :: var_lcl = [%d], var_glb[%d]\n", var_lcl, var_glb); } } else // fork failed { printf("\n Fork failed, quitting!!!!!!\n"); return 1; } return 0; } 

Ahora, cuando el código anterior se comstack y ejecuta:

 $ ./fork Parent process :: var_lcl = [10], var_glb[20] Child Process :: var_lcl = [1], var_glb[1]