2011-01-04 13 views
26

Tengo un programa con un proceso principal y uno secundario. Antes de la bifurcación(), el proceso principal se llamaba malloc() y rellenaba una matriz con algunos datos. Después de la bifurcación(), el niño necesita esa información. Sé que podría utilizar un tubo, pero el siguiente código parece funcionar:Específicamente, ¿cómo tenedor() maneja la memoria dinámicamente asignada de malloc() en Linux?

#include <stdio.h> 
#include <stdlib.h> 
#include <string.h> 
#include <unistd.h> 

int main(int argc, char *argv[]) { 
    char *array; 
    array = malloc(20); 
    strcpy(array, "Hello"); 
    switch(fork()) { 
    case 0: 
     printf("Child array: %s\n", array); 
     strcpy(array, "Goodbye"); 
     printf("Child array: %s\n", array); 
     free(array); 
     break; 
    case -1: 
     printf("Error with fork()\n"); 
     break; 
    default: 
     printf("Parent array: %s\n", array); 
     sleep(1); 
     printf("Parent array: %s\n", array); 
     free(array); 
    } 
    return 0; 
} 

La salida es:

Parent array: Hello 
Child array: Hello 
Child array: Goodbye 
Parent array: Hello 

Sé que los datos asignados en la pila está disponible en el niño, pero parece que los datos asignados en el montón también están disponibles para el niño. Y de manera similar, el niño no puede modificar los datos de los padres en la pila, el niño no puede modificar los datos de los padres en el montón. Así que supongo que el niño obtiene su propia copia de datos de pila y montón.

¿Este es siempre el caso en Linux? Si es así, ¿dónde está la documentación que lo respalda? Comprobé la página man de fork(), pero no mencionó específicamente la memoria asignada dinámicamente en el montón.

Gracias

Respuesta

30

Cada página que se asigna para el proceso (ya sea una página de memoria virtual que tiene la pila en él o la pila) se copia para el proceso en forma de horquilla para poder acceder a él.

En realidad, no se copia desde el principio, se establece en Copia en escritura, lo que significa que una vez que uno de los procesos (padre o hijo) intenta modificar una página, se copia para que no dañe unos a otros, y todavía tienen todos los datos desde el punto de fork() accesibles para ellos.

Por ejemplo, las páginas de códigos, aquellas a las que se asignó el ejecutable real en la memoria, son generalmente de solo lectura y se reutilizan entre todos los procesos bifurcados; no se copiarán nuevamente, ya que nadie escribe allí, solo leer, y entonces copiar-en-escribir nunca será necesario.

Más información está disponible here y here.

+0

Para que quede claro, hay * condición * de carrera en el código del OP, ¿correcto? – SiegeX

+3

No puede haber, los procesos ya no se pueden comunicar usando esta memoria. – abyx

+0

Nitpick: considere 'mmap (MAP_SHARED)' y 'shmat'. Que está fuera del alcance de "stack" y "heap" de C, pero dijiste "cada página" ... – ephemient

4

Después de un tenedor el niño es completamente independiente del padre, pero puede heredar ciertas cosas que son copias del padre. En el caso del montón, el niño tendrá conceptualmente una copia del montón de los padres en el momento de la bifurcación. Sin embargo, las modificaciones en el encabezado en el espacio de direcciones del niño solo modificarán la copia del niño (por ejemplo, mediante copia en escritura).

En cuanto a la documentación: Me he dado cuenta de que la documentación se suele afirmar que todo lo se copia, excepto de bla, bla, bla.

2

La respuesta corta es 'sucio al escribir' - la respuesta más larga es ... mucho más.

Pero para todos los fines: el modelo de trabajo que a nivel C es seguro asumir es que justo después de la horquilla() los dos procesos son absolutamente idénticos, es decir, el niño obtiene una copia 100% exacta (pero por un poquito alrededor del valor de retorno de fork()) - y luego comienzan a divergir a medida que cada lado modifica su memoria, apila y acumula.

Por lo tanto, su conclusión es leve: el elemento secundario comienza con los mismos datos que los padres copiados en su propio espacio, luego lo modifica y lo ve como modificado mientras el padre continúa con su propia copia.

En realidad, las cosas son un poco más complejas, ya que trata de evitar una copia completa haciendo algo sucio; evitando copiar hasta que tenga que hacerlo.

Dw.

Cuestiones relacionadas