CUESTIÓN

He seguido los consejos del LPE anterior. Sin embargo, ahora me ocurre una situación un tanto extraña. ¡Hay una variable que no funciona! El programa en esquema es como sigue:
     [[Código de iniciación, registro de SIGUSR1, etc.]]
     mi_hijo=fork();
     ...
     if (mi_hijo==0) /* Si soy el hijo menor */
         {kill(padre_de_todos, SIGUSR1);
          }
     for (;;) pause();
     [...]
     void manejadora(int seNal)
        {
         printf("Soy %d y voy a mandar la señal a %d.\n",
                getpid(),mi_hijo); fflush(stdout);
         /* kill(mi_hijo,SIGUSR1); */
         }
El hijo manda bien la señal al padre de todos porque se imprime el mensaje de la manejadora del padre, pero he tenido que comentar el kill porque mi_hijo vale 0. Su valor tiene que ser el pid del hijo del padre (lo que devolvió fork) pero vale 0. Es como si la variable global no funcionara. Además, en mi casa sí que funciona. Me estoy volviendo loco.

SOLUCIÓN

Si funciona en casa y en el servidor de la facultad no, el diagnóstico es claro: el programa está mal hecho.

El error no sale a la luz en Linux por la manera en que reparte la CPU. En una instrucción como mi_hijo=fork();, una vez ejecutada fork(), tenemos dos procesos, el padre y el hijo. Para el hijo, fork() devuelve 0. Para el padre, fork() devuelve el pid del hijo. Y ¡ojo!, que he dicho que fork() devuelve un valor. No he dicho cuándo el valor devuelto por fork() se va a almacenar en la variable. Justo en el momento en que fork se ha acabado de ejecutar, como nuestros ordenadores sólo tienen una CPU, el sistema operativo debe decidir quién prosigue su ejecución, el padre o el hijo. Ahí radica la diferencia entre Linux y el servidor de clase. Como no está especificado, Linux cede la CPU al padre primero. El servidor da la CPU al hijo en primer lugar. Veamos lo que ocurre en el servidor de clase que es el que hace aparecer el error:
  1. Justo después del fork, tenemos el padre y el hijo.
  2. En el servidor de clase, la CPU la toma el hijo. Manda la señal SIGUSR1 al padre.
  3. El padre se encuentra parado justo antes de almacenar el valor devuelto por fork() en la variable mi_hijo. Antes de poder hacerlo, el padre salta a la manejadora y, claro está que la variable contiene un cero.
La solución a este problema puede pasar por evitar que el padre pueda saltar a la manejadora antes de haber almacenado el valor de su variable. Esto se logra mediante el bloqueo de señales. Si un proceso bloquea una señal y esta señal se produce, el proceso no salta a la manejadora hasta que la señal sea desbloqueada. Para poder bloquear y desbloquear señales, podéis usar la llamada al sistema sigprocmask.
© 2003 Guillermo González Talaván.