pistolos.c
. La
correcta compilación de dicho programa, producirá un
fichero ejecutable, cuyo nombre será obligatoriamente
pistolos
. Respetad las mayúsculas/minúsculas
de los nombres, si las hubiere.
main
. A este proceso original se le pasará
por la línea de órdenes un número entero, correspondiente
con el número inicial de pistoleros que forman la partida.
El número estará comprendido entre 3 y 128.
*** COMIENZA LA RONDA NUMERO 7 *** *** PIDs: 1234 1689 1748 2222Acto seguido, enviará una señal
SIGUSR1
a
cada uno de ellos para indicarles que pueden elegir al compañero
y dispararle.
SIGTERM
a
dicho pistolero, para matarlo.
1234->1689 2222->1689 1748->2222 1689->1748Debe aparecer, por lo tanto, una línea por cada proceso indicando a qué proceso ha disparado. No tienen por qué aparecer en orden. Dependerá de cómo reparta el Sistema Operativo la CPU. Y también deben disparar todos los pistoleros, incluso aunque les haya llegado un disparo antes.
wait
s como procesos pistoleros había
antes de disparar y, de este modo, sabrá qué procesos
han muerto a causa de los disparos.
wait
s. Esto lo logra el propio proceso padre,
mediante una llamada previa a
a alarm
antes de dormirse.
La llamada hará que el Sistema Operativo le envíe una
señal SIGALRM cuando pase un segundo.
system
, salvo indicación explícita en
el enunciado de la práctica.
pause()
. Compiladlo, ejecutadlo,
comprobadlo con ps -fu
y
depuradlo, si fuera necesario.
sigaction
.
sigprocmask
SIGUSR1 en la zona
conflictiva y desbloquearla cuando no tenga
peligro el recibirla (quizá en un
sigsuspend
).
pause
de padre
por llamadas a wait
para que recoja
el código de retorno de los pistoleros
muertos.
rand()
.
Con cuidado, pues todos los procesos deben
llamar a srand()
para iniciar el
generador y lo suyo es que cada pistolero,
cuando nació haya llamado a esa función
con un argumento diferente de modo que obtengan
números diferentes y no todos maten al mismo.
Una idea es que el PID del proceso participe
en la fórmula que pongáis como argumento
a srand()
.
wait
s y algunos hijos muertos y otros
que se han librado. A no ser que dé la
casualidad de que se mueran todos, el padre
se va a quedar atrapado en los wait
s
para siempre. Como dice el enunciado que la
espera es como máximo de 1 segundo, la mejor
solución es usar alarm
para que,
al cabo de un segundo, el sistema operativo
despierte al padre con un SIGALRM
SIGALRM
tiene ese
comportamiento por defecto. Tenéis que
evitar que eso ocurra y tenéis que diferenciar
el despertar del padre de un wait
debido a que recibe SIGALRM
del
despertar debido a que se ha muerto un hijo.
SIGALRM
en cualquier momento, seguro que cuando no
fuera conveniente. La solución a esto
pasa por desarmar el alarm
en ese
caso (muerte de todos).
sleep()
o
similares para sincronizar los procesos. Hay que
usar otros mecanismos.
pause()
.
Salvo en bucles infinitos de pause
s,
su uso puede estar mal. Mirad la solución a la
práctica
propuesta en la sesión quinta acerca de él o el
siguiente LPE.
open
o
creat
, read
, write
y close
. No debéis usar las de la familia
de fopen
. Si necesitáis escribir o leer
algo con formato, usad las funciones sprintf
y sscanf
como intermediarias.
fork(); [] ... bucle_de_rondas: sigsuspend(); [SIGUSR1] elegir_hermano(); [] disparar_hermano(); [] sigsuspend(); [SIGTERM, SIGUSR2] fin_bucle_de_rondas;Entre corchetes se han puesto las señales que se permiten en cada instrucción. Si aparece vacío es que todas están bloqueadas.
sigsuspend
de SIGUSR2 primero y el de
SIGUSR1 después antes de que los
demás hayan pasado del de SIGUSR2. El resultado es
que dispara y esa bala, que es de la siguiente ronda,
no lo olvidemos, impacta en el pistolero en la ronda
anterior y la cosa falla. Como solución, que podéis
usar, propone el compañero que el padre espere
otro segundo, con alarm
antes de volver a
mandar SIGUSR1. Podéis ver con esta práctica lo
mala que es efectivamente la sincronización con
señales. Todos estos problemas se solucionarán
asépticamente con los mecanismos que veremos a partir
de las siguientes sesiones.