Publi

Variables compartidas entre procesos hijos en C [fork()]

Otra forma de enfrentarse con la concurrencia, en el maravilloso mundo de hacer varias cosas al mismo tiempo, es utilizar procesos hijos con fork(). La principal diferencia con respecto a los threads es que éstos son procesos completos, es decir, el sistema operativo les ha dado una zona de memoria de código, otra de datos, y otra de pila, a diferencia de los threads que compartían código y datos, sólo tenían la pila diferente.

Pero, ¿qué pasa si queremos compartir información entre nuestros procesos hijo? En principio, si lo intentamos hacer como con los threads, no va a funcionar, precisamente porque al ser procesos diferentes, utilizarán zonas diferentes de memoria para almacenar sus datos. Por ejemplo, si hacemos:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <stdint.h>
#include <string.h>
#include <sys/wait.h>

int main()
{
  int child;
  int *number = (int*)malloc(sizeof(int));
  int i;

  *number = 10;

  child = fork();

  if (child==-1)
    {
      exit(1);
    }
  else if (child==0)
    {
      for (i=0; i<10; ++i)
    {
      usleep(100);
      printf ("CHILD -- Number: %d\n", *number);
      *number=i;
    }
      exit(0);
    }
  else
    {
      for (i=20; i<30; ++i)
    {
      usleep(100);
      printf ("MAIN -- Number: %d\n", *number);
      *number=i;
    }
    }
  wait(NULL);
  free(number);
}

Lo ideal sería que el proceso pricipal (MAIN) fuera capaz de ver el valor que ha dejado el hijo (CHILD) y viceversa, pero no, son valores totalmente independientes… y mira que hemos reservado memoria aparte con malloc. Es que un fork() copiará los valores de todas las variables en el momento del fork, pero el espacio en memoria es diferente.

Para ello tenemos que hacer uso de la memoria compartida, para ello, en lugar de malloc, vamos a utilizar:

1
2
  int *number = (int*)mmap(NULL, sizeof(int), PROT_READ | PROT_WRITE,
               MAP_SHARED | MAP_ANONYMOUS, -1, 0);

Para utilizar mmap() debemos incluir la biblioteca <sys/mman.h>

Al igual que con malloc() utilizamos free() para liberar la memoria, con mmap() utilizaremos:

1
munmap(number, sizeof(int));

Aunque del mismo modo que utilizando hilos podíamos tener problemas de condición de carrera, en este caso estamos en las mismas por lo que se aconseja el uso de mutex.
De esta forma podremos utilizar una zona común para almacenar esta información, y ahora sí que el CHILD verá el valor del MAIN y viceversa.
Foto: Rudolf Vicek (Flickr) CC-by

También podría interesarte...

There are 3 comments left Ir a comentario

  1. Pingback: Creando un mutex con semáforos entre procesos hijos en C [fork()] | Poesía Binaria /

  2. Maury /
    Usando Google Chrome Google Chrome 62.0.3202.94 en Linux Linux

    Hola! asi tal cual pones en tu codigo a mi no me funciona. Cuando compilo me genera estos errores:

    UDP.cpp:390:19: error: invalid conversion from ‘void*’ to ‘int*’ [-fpermissive]
    int *envio = mmap(NULL, sizeof(int), PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANONYMOUS, -1, 0);
    ^
    UDP.cpp:509:31: error: ‘mmunmap’ was not declared in this scope
    mmunmap(envio, sizeof(int));

    1. Gaspar Fernández / Post Author
      Usando Mozilla Firefox Mozilla Firefox 57.0 en Linux Linux

      Muy cierto. Voy a arreglar el contenido del post. Básicamente será meter algunos #include más y poner el tipo de variable a la salida de mmap(). Yo creo que eso es lo que te da problemas, que tendríamos que hacer:
      int *envio = (int*) mmap(NULL, sizeof(int), PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANONYMOUS, -1, 0);

      Por lo de mmunmap(), la función se llama munmap(), se me coló una “m” de más.

      Muchas gracias por tu comentario!

Leave a Reply