wait, waitpid y waitid, gestión de múltiples procesos

    Tras ver como se pueden generar varios procesos empleando fork ahora veremos como podemos controlar sus tiempos de ejecución con wait, waitpid y waitid.

    Esta es la firma de las dos primeras funciones:

pid_t wait(int *status)
pid_t waitpid(pid_t pid, int *status, int options)

    Estas funciones se utilizan para esperar hasta que un proceso cambie de estado. Se emplean como ya hemos comentado para esperar por un cambio de estado en un proceso hijo del proceso que realiza la llamada ha estas funciones. Un cambio de estado para el proceso hijo puede ser uno de estos 3: el hijo ha muerto, el hijo ha sido detenido por una señal o el hijo continua su ejecución tras recibir una señal apropiada (resume).

    Si el hijo ha cambiado de estado antes de la ejecución del wait entonces la llamada a esta función retornará inmediatamente. En caso contrario la llamada bloqueará el proceso hasta que se produzca este cambio de estado.

    wait() espera hasta que uno cualquiera de los hijos del proceso que realiza la llamada a wait cambie de estado. waitpid en su lugar suspende la ejecución del proceso actual hasta que el hijo, especificado por el argumento pid cambie su estado. Por defecto, waitpid espera sólo por la muerte de los hijos, pero este comportamiento es modificable mediante el parámetro options.

    El valor de pid puede tomar estos valores

    Más pequeño que -1 hace que se espere por cualquier hijo cuyo id de proceso de grupo sea igual al valor absoluto de este argumento. Igual a -1 esperará por cualquier hijo, el primero en cambiar de estado (igual comportamiento que wait), cero indica que se esperará por cualquier proceso hijo que tenga el mismo id de grupo de procesos y mayor que cero hará que se espere por el hijo cuyo pid coincida con este valor.

    El parámetro optiones es una máscara OR de diversos constantes, sólo las enumeraré pero es sencillo encontrar información sobre ellas utilizando el comando man: WHOHANG, WUNTRACED, WCONTINUED, WIFEXITED, WEXITSTATUS, WIFSIGNALED, WTERMSIG, WCOREDUMP, WIFSTOPPED, WSTOPSIG y WIFCONFIRMED

    Existe además otra función llamada waitid que realiza una función análoga a las anteriores pero proporciona un mayor control sobre que cambios de estado en el hijo deben ser esperados. La firma de la función es la siguiente

int waitid(idtype_t idtype, id_t id, siginfo_t *infop, int options)

    Los archivos de cabecera donde se definen estas 3 funciones y las constantes y tipos necesarios para su utilización están en los archivos de cabecera sys/types.h y sys/wait.h

    Los parámetros id e idtype seleccionan a que hijo(s) se debe esperar, options tiene el mismo significado que en el caso de waitpid().

    En cuanto a los los parámetros que retornas estas tres funciones wait() en caso de éxito devuelve el pid del proceso hijo que ha cambiado de estado. En caso de error devuelve -1. waitpid() en caso de éxito devuelve lo mismo que wait() y en caso de error -1 pero si se ha especificado la constante WHOHANG la función no bloquea y devuelve cero si no hay ningún hijo que haya cambiado de estado. Por último waitid() devuelve cero en caso de éxito o si WHOHANG ha sido activado y no hay hijo que haya cambiado de estado y -1 en caso de error.

    Volviendo a nuestro programa fork vamos ha hacerle unas modificaciones para que el padre espere a la muerte de sus 2 hijos:

#include <sys/types.h>
#include <unistd.h>
#include <stdio.h>

int main(int argc, char *argv[])
{
	pid_t pid1, pid2;
	int status1, status2;

	if ( (pid1=fork()) == 0 )
	{ /* hijo */
		printf("Hijo 1 (%d, hijo de %d)\n",  getpid(), getppid());
	}
	else
 	{ /*  padre */
 		if ( (pid2=fork()) == 0 )
 		{ /* segundo hijo  */
 			printf("Hijo 2 (%d, hijo de %d)\n",  getpid(), getppid());
		}
		else
		{ /* padre */
/* Esperamos al primer hijo */
			waitpid(pid1, &status1, 0);
/* Esperamos al segundo hijo */
			waitpid(pid2, &status2, 0);
			printf("Padre (%d, hijo de %d)\n", getpid(), getppid());
 		}
	}

	return 0;
}

    waitpid hace que se espere hasta que terminen los dos hijos identificados en el programa por pid1 y pid2

    Para compilar y ejecutar este programa copia el fragmento de código en un fichero llamado forks.c y después en el mismo directorio donde lo has grabado ejecuta las siguientes líneas

$ gcc forks.c
$ ./a.out

Recuerda que para ver la pid de la shell donde ejecutas el programa debes ejecutar:

$ echo $$

Fork en Linux

    Existen multitud de programas que mantienen varios procesos para poder atender distintas tareas, resolver en paralelo una tarea compleja o ser más eficientes en las respuestas al usuario. Para ello el programa debe ser capaz de lanzar procesos hijos con capacidad para realizar distintas tareas. Cada proceso es completamente independiente pero puede comunicarse con otros empleando fifos o memoria compartida. Una de las estrategias principales que se emplean con este tipo de programa multiproceso es crear un padre y varios hijos, el padre gestiona la creación, destrucción y administración de los procesos hijos. Un buen ejemplo de este comportamiento lo tenemos en el servidor web apache funcionando en modo MPM (Multi-processing Module). Utiliza una estrategia de este tipo para atender múltiples peticiones simultaneas http procedentes de clientes externos. Veamos como consigue hacer esto.

    Para poder iniciar procesos adicionales en una máquina GNU/Linux, procesos adicionales al que se están ejecutando, se emplea el comando fork cuya firma es la siguiente

pid_t fork(void);

    Su definición se encuentra en los archivos de cabecera sys/types.h y unistd.h. En unistd.h está definida la función y en types.h el tipo pid_t que no es más que un identificador de proceso linux PID.

    Fork crea un proceso hijo que se diferencia de su creador únicamente por su PID y por su PPID (Parent PID, identificador del proceso padre del proceso actual). Además el proceso hijo no hereda los bloqueos de fichero ni las señales pendientes de su padre, en otro artículo hablaremos del clone que si los hereda.

    Tras la creación del proceso hijo ambos procesos son ejecutados en «paralelo«, es decir, tenemos dos procesos ejecutando el código del programa. La diferencia entre los dos se haya en lo que devuelve la llamada al fork. En cada uno de esos procesos este valor es diferente, para el proceso padre fork devuelve el PID del proceso recién creado y para el proceso recién creado fork devuelve 0, además el PPID del proceso recién creado es el PID del proceso padre (lógico).

    Para conocer el PID y el PPID de un proceso se pueden emplear las funciones getpid y getppid respectivamente. Nuevamente estas funciones están definidas en el archivo de cabecera unistd.h con la siguiente firma:

__pid_t getpid (void)
__pid_t getppid (void)

Ejemplo de fork:

#include <sys/types.h>
#include <unistd.h>
#include <stdio.h>

int main(int argc, char *argv[])
{
        pid_t pid;

        pid = fork();

        if(pid==-1)
        {
                printf("Fallo al forkear\n");
                return -1;
        }
        else if (!pid)
        {
                printf("Proceso hijo: PID %d - PPID %d\n", getpid(), getppid());
        }
        else
        {
                printf("Proceso padre: PID %d - PPID %d\n", getpid(), getppid());
        }
        return 0;
}

    Prueba el programa y observa su salida.

    Nota: si quieres conocer el PID del proceso bash de tu consola puedes ejecutar

$ echo $$

    Este debería corresponderse con el PPID del proceso padre que acabas de crear

    Seguiremos con este tema en próximos días

Hamilton gana en Australia

    Lewis Hamilton (McLaren-Mercedes) ha vencido en el gran premio de Australia, la primera prueba puntuable para el campeonato del mundo de Formula 1. Estos han sido los resultados

1. Hamilton 1:34:50.616
2. Heidfeld a 5.478
3. Rosberg a 8.163
4. Alonso a 17.181
5. Kovalainen a 18.014
6. Nakajima a 1 vuelta
7. Bourdais a 3 vueltas
8. Raikonen a 5 vueltas

    Asombrosamente sólo acabaron 8 pilotes en un gran premio muy accidentado. Las nuevas normas de la FIA limitando ciertos elementos que ayudaban a la conducción han sido los principales responsables. Ahora los pilotos tienen más peso real en el resultado de las carreras lo que me parece una buena noticia para el espectáculo y para este deporte.

    En cuanto a los resultados Hamilton ha sido el justo vencedor a pesar de que los 2 coches de seguridad que se vieron en carrera le favorecieron. Es destacable también que Alonso consiguiera alcanzar el 4 puesto después de salir de la 11 posición. Otro punto a destacar ha sido la mala carrera de los Ferrari donde Raikonen fue el único en hacer puntos y ¡eso que acabo de último!. Más carreras locas como estas nos esperan. Enhorabuena a todas las aficionados.

Ataques y daños

    Se han implementado el comando de ataque y los daños sobre los personajes lo que convierte a RPG-WEB en cercano a ser realmente jugable. Se han añadido un buen numero de tilesets y el editor de mapas es ya funcional. La aplicación no es completamente estable debido ha algunos cambios destacables en las comunicaciones cliente-servidor.

    Pasos a seguir:

  • Creación de un subdominio donde alojar la primera pre-alpha del juego
  • Implementar saltos incondicionales que harán que un personaje cambie automáticamente de mapa al pisar una casilla
  • Implementación de trampas

El voto emigrante amplia la ventaja del PSOE sobre el PP

    El voto de los españoles residentes en el extranjero permitió al PSOE incrementar en poco más de un millón de votos su ventaja sobre el PP en las elecciones del pasado domingo. Los socialistas obtuvieron 217.686 sufragios de los emigrantes y los populares, 106.265. Incorporadas estas papeletas al recuento definitivo, el partido gubernamental alcanzó los 11.282.210 votos, el 43,8% del total, por 10.276.238 de la oposición, el 39,9%.

    A pesar de la contundencia de las cifras, el PSOE no rentabilizó en escaños esta situación y, en cambio, el PP sí lo hizo. Gracias al voto emigrante, los populares se hicieron con el último diputado por Barcelona y se lo arrebataron a CiU, que lo había ganado en el primer escrutinio de votos del domingo. Coalición Canaria, a su vez, logró gracias a estos sufragios dos senadores por El Hierro y Santa Cruz de Tenerife, en la primera isla se lo quitaron al PP, y en la segunda al PSOE, si bien ambas formaciones han impugnado el recuento.

Varios muertos y heridos en Tíbet en una protesta contra la ocupación china

    La capital tibetana, Lhasa, vivió ayer los peores disturbios de los últimos 20 años, después de varios días de protestas de los monjes budistas que han dejado hasta el momento al menos dos muertos y una docena de heridos, según los servicios médicos de urgencias. Asimismo, dos monjes se encuentran en estado crítico tras infligirse heridas para mostrar su «desesperación», y numerosos religiosos permanecen en huelga de hambre en sus monasterios, que han sido rodeados por las fuerzas de seguridad chinas. Además, varios establecimientos y coches han resultado incendiados en el centro de la ciudad.

Elecciones en Irán

    44 millones de Iranies están llamados hoy a las urnas para renovar su parlamento. Muchas personas afines al actual presidente iraní Mahmoud Ahmadinejad se han vuelto en su contra debido a su política económica. Aunque quizás el plan de desarrollo de más envergadura y ambicioso de Ahmadinejad haya sido sin lugar a dudas su programa nuclear que ha colocado a Irán en el punto de mira de muchas naciones. Aunque según los iranies el plan de desarrollo nuclear es para fines pacíficos gobiernos extranjeros lo ven como un camino para el desarrollo de armas atómicas. Irán es uno de los países firmantes del acuerdo de no proliferación de armas nucleares (subscrito en 1968 y prorrogado indefinidamente en 1995)

    En Irán la política y la religión están intimamente ligados, de hecho, es posible votar en las mezquitas.