Ya no necesitas buscar más por todo internet porque estás al sitio necesario, poseemos la solución que necesitas pero sin complicarte.
Solución:
fork()
dice “copie el estado actual del proceso en un nuevo proceso e inícielo desde aquí”. Debido a que el código se ejecuta en dos procesos, de hecho devuelve dos veces: una en el proceso padre (donde devuelve el identificador de proceso del proceso hijo) y una vez en el proceso hijo (donde devuelve cero).
Hay muchas restricciones sobre lo que es seguro llamar en el proceso secundario después fork()
(vea abajo). La expectativa es que el fork()
La llamada fue parte de la generación de un nuevo proceso que ejecuta un nuevo ejecutable con su propio estado. La segunda parte de este proceso es un llamado a execve()
o una de sus variantes, que especifica la ruta a un ejecutable que se cargará en el proceso que se está ejecutando actualmente, los argumentos que se proporcionarán a ese proceso y las variables de entorno para rodear ese proceso. (No hay nada que le impida volver a ejecutar el ejecutable que se está ejecutando actualmente y proporcionar un indicador que hará que continúe donde lo dejó el padre, si eso es lo que realmente desea).
El UNIX fork()-exec()
dance es aproximadamente el equivalente de Windows CreateProcess()
. Una función más nueva se parece aún más a ella: posix_spawn()
.
Como ejemplo práctico de uso fork()
, considere un caparazón, como bash
. fork()
es utilizado todo el tiempo por un shell de comandos. Cuando le dice al shell que ejecute un programa (como echo "hello world"
), se bifurca y luego ejecuta ese programa. Una canalización es una colección de procesos bifurcados con stdout
y stdin
arreglado apropiadamente por el padre en el medio fork()
y exec()
.
Si desea crear un nuevo hilo, debe usar la biblioteca de hilos de Posix. Creas un nuevo hilo Posix (pthread) usando pthread_create()
. Tu CreateNewThread()
ejemplo se vería así:
#include
/* Pthread functions are expected to accept and return void *. */
void *MyFunctionToRun(void *dummy __unused);
pthread_t thread;
int error = pthread_create(&thread,
NULL/*use default thread attributes*/,
MyFunctionToRun,
(void *)NULL/*argument*/);
Antes de que los hilos estuvieran disponibles, fork()
fue lo más parecido que UNIX proporcionó a los subprocesos múltiples. Ahora que los hilos están disponibles, el uso de fork()
se limita casi por completo a generar un nuevo proceso para ejecutar un ejecutable diferente.
a continuación: Las restricciones se deben a fork()
es anterior al subproceso múltiple, por lo que solo el subproceso que llama fork()
continúa ejecutándose en el proceso hijo. Por POSIX:
Se creará un proceso con un solo hilo. Si un proceso de múltiples subprocesos llama a fork (), el nuevo proceso contendrá una réplica del subproceso que realiza la llamada y su espacio de direcciones completo, posiblemente incluyendo los estados de mutex y otros recursos. En consecuencia, para evitar errores, el proceso hijo solo puede ejecutar operaciones seguras de señal asíncrona hasta que se llame a una de las funciones ejecutivas. [THR] [Option Start] Los manejadores de bifurcaciones pueden establecerse mediante la función pthread_atfork () para mantener invariantes de aplicación en las llamadas a fork (). [Option End]
Cuando la aplicación llama a fork () desde un manejador de señales y cualquiera de los manejadores de fork registrados por pthread_atfork () llama a una función que no es asynch-signal-safe, el comportamiento es indefinido.
Debido a que cualquier función de biblioteca a la que llame podría haber generado un hilo en su nombre, la suposición paranoica es que siempre está limitado a ejecutar operaciones seguras de señal asíncrona en el proceso secundario entre llamadas fork()
y exec()
.
Dejando a un lado la historia, existen algunas diferencias fundamentales con respecto a la propiedad de los recursos y el tiempo de vida entre procesos e hilos.
Cuando se bifurca, el nuevo proceso ocupa un espacio de memoria completamente separado. Esa es una distinción muy importante de la creación de un nuevo hilo. En las aplicaciones de subprocesos múltiples, debe considerar cómo accede y manipula los recursos compartidos. Los procesados que se han bifurcado deben compartir recursos explícitamente utilizando medios entre procesos, como memoria compartida, tuberías, llamadas a procedimientos remotos, semáforos, etc.
Otra diferencia es que los niños con fork () ‘ed pueden sobrevivir a sus padres, mientras que todos los hilos mueren cuando el proceso termina.
En una arquitectura cliente-servidor donde se espera un tiempo de actividad muy, muy largo, usar fork () en lugar de crear subprocesos podría ser una estrategia válida para combatir las pérdidas de memoria. En lugar de preocuparse por limpiar las pérdidas de memoria en sus hilos, simplemente bifurca un nuevo proceso secundario para procesar cada solicitud del cliente y luego mata al niño cuando haya terminado. La única fuente de pérdidas de memoria sería el proceso padre que distribuye eventos.
Una analogía: puede pensar en la generación de subprocesos como abrir pestañas dentro de una sola ventana del navegador, mientras que la bifurcación es como abrir ventanas separadas del navegador.
Sería más válido preguntar por qué CreateNewThread
no solo devuelve una identificación de hilo como fork()
hace … después de todo fork()
sentar un precedente. Tu opinión está influida por haber visto uno antes que el otro. Da un paso atrás y considera que fork()
duplica el proceso y continúa la ejecución … ¿qué mejor lugar que en la siguiente instrucción? ¿Por qué complicar las cosas agregando una llamada de función al trato (y luego una que solo requiere void*
)?
Tu comentario para Mike dice “No puedo entender en qué contextos querrías usarlo”.. Básicamente, lo usa cuando quiere:
- ejecutar otro proceso usando la familia de funciones ejecutivas
- realizar algún procesamiento paralelo de forma independiente (en términos de uso de memoria, manejo de señales, recursos, seguridad, robustez), por ejemplo:
- cada proceso puede tener límites intrusivos de la cantidad de descriptores de archivo que pueden administrar, o en un sistema de 32 bits, la cantidad de memoria: un segundo proceso puede compartir el trabajo mientras obtiene sus propios recursos
- Los navegadores web tienden a bifurcar procesos distintos porque pueden realizar algo de inicialización y luego llamar a las funciones del sistema operativo para reducir permanentemente sus privilegios (por ejemplo, cambiar a una identificación de usuario menos confiable, cambiar el directorio “raíz” bajo el cual pueden acceder a los archivos, o hacer algunos páginas de memoria de solo lectura); la mayoría de los sistemas operativos no permiten el mismo grado de configuración de permisos detallados por subproceso; Otro beneficio es que si un proceso secundario tiene fallas seguras o similar, el proceso principal puede manejar eso y continuar, mientras que fallas similares en el código de múltiples subprocesos plantean preguntas sobre si la memoria se ha corrompido, o se han retenido bloqueos, por el subproceso que falla de manera que los hilos restantes están comprometidos
Por cierto, usar UNIX / Linux no significa que tenga que renunciar a los subprocesos por fork()
procesos de ing … puedes usar pthread_create()
y funciones relacionadas si se siente más cómodo con el paradigma de subprocesamiento.
Te mostramos reseñas y puntuaciones
Si conservas algún titubeo o forma de enriquecer nuestro noticia te mencionamos añadir un exégesis y con gusto lo observaremos.