PRÁCTICAS DE LABORATORIO DE SISTEMAS OPERATIVOS
PRIMERA PRÁCTICA EVALUABLE (2005-06)
Infinito
Enunciado.
El programa que hay que presentar constará de un único
fichero fuente de nombre infinito.c
. La
correcta compilación de dicho programa, producirá un
fichero ejecutable, cuyo nombre será obligatoriamente
infinito
. Respetad las mayúsculas/minúsculas
de los nombres, si las hubiere.
La ejecución del programa creará una serie de procesos
que se transmitirán señales entre ellos.
En concreto, el árbol de procesos que hay que
crear es el siguiente:
Para comprender mejor el funcionamiento de la práctica,
cambiemos la posición de los procesos en el dibujo de forma
que formen una figura semejante al símbolo de infinito:
Las
relaciones paterno-filiales son las indicadas por las líneas
sólidas.
Durante treinta segundos, deben estar circulando señales
entre los procesos en el sentido que indican las flechas rojas
de la figura. El tipo de señal o señales usadas se deja
libre. El proceso padre es el que controlará estos treinta
segundos (no usad sleep
).
Transcurridos los treinta segundos, el proceso padre dejará
de enviar señales, arbitrará un mecanismo para que los procesos
mueran (o se maten), esperarán a que hayan muerto y escribirá
por la salida estándar "La señal ha dado x vueltas.",
donde x será el número de vueltas que ha dado la señal
a los procesos del dibujo.
Los procesos, una vez creados, deben permanecer bloqueados,
sin consumir CPU mientras esperan a recibir la señal y enviar
esa u otra al siguiente proceso.
Si se requiere sincronizar alguna acción, se pueden usar
señales, pero la espera se debe realizar sin
consumo de CPU. Para simplificar el problema, podéis
suponer que al ser mandada la señal inicial manualmente,
ya ha habido tiempo suficiente para que todos los procesos
hayan sido creados para cuando el primer proceso la reciba.
Sin embargo, esta concesión en aras de simplificación, no
implica suponer ninguna condición, incluida ésta, en ninguna
otra parte de la práctica.
Para ver si habéis conseguido crear el árbol de procesos
correctamente, podéis descargaros el siguiente ejecutable:
Arbol_dominO. No os va a
funcionar en Linux, pues es un ejecutable binario y los
procesadores son diferentes.
Desde el servidor, para
ver el árbol de procesos que habéis generado, usad la
orden: ps -f | grep "infinito$" | grep -v grep | sort |
Arbol_dominO
. Si os aparece el mensaje
"Árbol con múltiples raíces. Se aborta.
",
significa que habéis corrido varias veces vuestra práctica
sin matar los procesos de la anterior.
En el caso de Linux, podéis usar la opción -f
de la
orden ps
.
Restricciones
- Se deberán usar llamadas al sistema siempre que sea
posible, a no ser que se especifique lo contrario.
- No está permitido usar la función de biblioteca
system
, salvo indicación explícita en
el enunciado de la práctica.
- Para generar el árbol de procesos, no se usarán
llamadas al sistema de la familia
exec
.
- No se puede suponer que los PIDs de los procesos
de una ristra van a aparecer consecutivos. Puestos
en plan exquisito, ni siquiera podemos suponer que
estarán ordenados de menor a mayor (puede ocurrir
que se agoten los PIDs y retome la cuenta partiendo
de cero).
- No está permitido el uso de ficheros, tuberías u
otro mecanismo externo para transmitir información
entre los procesos.
Plazo de presentación.
Hasta el jueves, 23 de marzo de 2006, inclusive.
Normas de presentación.
Acá están.
LPEs.
- Las tareas que tiene que realizar el
programa son variadas. Os recomiendo que vayáis
programándolas y comprobándolas una a una. No es muy
productivo hacer todo el programa de seguido y corregir
los errores al final. El esquema que os recomiendo
seguir para facilitaros la labor se os muestra a
continuación:
- Haced un pequeño programa que cree los procesos
H1, H2, H3 y H4. Compiladlo, ejecutadlo,
comprobadlo con
Arbol_dominO
y
depuradlo, si fuera necesario.
- Repetid el procedimiento con los procesos
N2 y N3.
Alternativamente, podéis intentar generar
los procesos mediante un bucle, sin hacerlo
en el código explícitamente.
- Una vez el árbol esté bien generado, comprobad
que los procesos no consumen CPU con
top
.
- Es mejor que a continuación resolváis el problema
de matar a los procesos y los treinta segundos.
Debéis usar SIGALRM en el proceso padre para que,
transcurridos los treinta segundos salte a la
manejadora y mate todos los procesos. El esquema
para que los procesos mueran lo podéis hacer como
gustéis, aunque lo más natural es que los padres
vayan matando a los hijos y esperen por su muerte
con
wait
s. De momento, que el
proceso padre ponga que se han dado cero vueltas.
También, para trabajar y depurar con más
comodidad, sustituid temporalmente los treinta
segundos por cinco.
- Localizad en vuestro programa el código que
ejecuta el proceso H2. Construid para ese
proceso una manejadora que intercepte
SIGUSR1
, por ejemplo. Dentro de esa
manejadora, poned un mensaje indicando que se
ha recibido la señal. Que P le mande la señal a
H2. Comprobad y corregid si no funciona.
- Localizad el código de N2 y repetid lo hecho con
H2 en el paso anterior. Dentro de la manejadora
de H2 le enviáis la señal a N2. Comprobad y
corregid si no funciona.
- Repetid el esquema para la pareja N2-H1. Aquí
os encontraréis con un problema que debéis
discurrir cómo resolverlo. Para que N2 mande
la señal a H1 es necesario que conozca su PID.
No podéis usar un fichero para transmitirlo.
- La siguiente dificultad os la encontraréis
cuando H4 tenga que mandar la señal a P, justo
al final del recorrido. P debe diferenciar la
señal que le llega de H4 de la que le llega de
H1. Hay que volver a pensar.
- Completad la práctica haciendo que el padre
cuente las vueltas y completando los detalles
del enunciado que os falten.
- Para matar los procesos después de cada ejecución,
hay una manera muy cómoda. Si habéis usado
"
infinito &
" para ejecutar la práctica,
podéis usar "kill %
" para matar a todos
los procesos de golpe.
- No se puede usar
sleep()
o
similares para sincronizar los procesos. Hay que
usar otros mecanismos.
- Sabéis que si usáis espera ocupada en lugares
donde explícitamente no se haya dicho que se puede
usar, la práctica está suspensa. No obstante, existe
existe una variedad de espera ocupada que podríamos
denominar espera semiocupada. Consiste en
introducir una espera de algún segundo en cada iteración
del bucle de espera ocupada. Con esto el proceso no
consume tanta CPU como en la espera ocupada, pero persisten
los demás problemas de la técnica del sondeo, en particular
el relativo a la elección del periodo de espera.
Aunque la práctica no estará suspensa si hacéis espera
semiocupada, se penalizará en la nota bastante si la
usáis. En conveniente que la evitéis.
- Evitad, en lo posible, el uso de variables globales.
Tenéis la posibilidad de declarar variables
estáticas.
- Tened cuidado con el uso de
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.
- Es conveniente que, antes de entregar la práctica,
comprobéis que los
kill
s están enviando la
señal a los procesos correctos. Si al imprimirlo resulta
que a veces mandan la señal al proceso "0", es que está
mal. Lo que ocurre es que el proceso que realiza el
kill
recibe la señal y
salta a la manejadora antes de actualizar la
variable que contiene el pid de su hijo. Por eso la
variable tiene 0. La solución consiste en que el
patriarca bloquee la señal y cada proceso la
desbloquee justo antes de quedarse parado y después de
haber hecho todas sus tareas.
- El programa que he hecho se para a veces.
O en mi casa se para, pero en clase, no.
O en clase sí, pero en casa, no.
Solución.
- ¿Qué hago cuando mi programa se desboca
para no perjudicar el funcionamiento de la
máquina?
Solución.
- La práctica en ejecución os va a consumir CPU. La razón
es que las señales están circulando sin descanso. Esto
es normal siempre que tengáis bien programado el
sigsuspend
. Un efecto curioso del que se
ha dado cuenta un compañero es que el proceso padre
consume el doble de CPU que los demás debido a que por
él las señales pasan dos veces en una vuelta. Esto es
síntoma de que la práctica funciona.
Prácticas propuestas en años anteriores.
© 2006 Guillermo González Talaván y
Susana Álvarez Rosado.