Enunciado.
El programa propuesto constará de un único fichero fuente,
parking.cpp, cuya adecuada compilación producirá
el ejecutable parking. Se trata de simular mediante
un programa que realice llamadas a la API de WIN32
la gestión de memoria de un sistema operativo que use
particiones de tamaño dinámico. Para ello, se establece el
símil con el problema de elegir el mejor aparcamiento para un coche
de todos los posibles en una acera. Según se va ejecutando el programa,
se ha de ver una imagen parecida a la siguiente:
En la imagen puede observarse de color marrón lo que simulan ser cuatro
aceras. El algoritmo que se usa para aparcar los coches en cada
una corresponde, de arriba a abajo, al primer ajuste,
siguiente ajuste, mejor ajuste y peor ajuste,
tal y como se vio en la primera parte de la asignatura. Cada acera
consta de ochenta caracteres (0-79) y los coches tienen longitud entera,
medida en caracteres.
Quizá de los cuatro algoritmos el que mayor dificultad presente sea
el del siguiente ajuste. Cuando un coche llega a aparcar, de
todos los huecos en los que cabe el coche, se elige el primero que
aparece a partir de la posición en la que aparcó el último coche.
Si se llega al final de la acera, se vuelve a empezar por el
principio.
El algoritmo no presenta mayor problema salvo cuando el último coche
que aparcó ya se ha ido. En ese caso, si el extremo izquierdo que
ocupó ese último coche pertenece actualmente a un hueco, dicho hueco
será elegido sólo en el caso de que no haya otro disponible. Si dicho
extremo corresponde con un coche aparcado, se empezará a considerar
huecos a partir del final de ese coche.
En el caso de los algoritmos del mejor ajuste y del
peor ajuste, si hay empate entre dos o más huecos, se elegirá
entre ellos siguiendo el criterio del primer ajuste.
Una vez elegido un hueco con espacio suficiente para aparcar el coche,
se aparcará ajustando el coche a la izquierda del hueco en cualquiera
de los algoritmos.
Si cuando llega un coche, no existe un hueco de tamaño suficiente para
que aparque, el coche se pondrá en una cola a la espera de que otro
coche salga del aparcamiento. Esta cola seguirá una disciplina FIFO.
La simulación durará 30 segundos, terminados los cuales el programa
presentará una serie de estadísticas resultantes de la simulación para
cada uno de los algoritmos. Las estadísticas se referirán sólo a
los coches totalmente atendidos
(aquellos que han aparcado y ya han consumido su tiempo de espera
aparcando y están dispuestos para salir). En concreto, se pedirá:
- Media de la longitud de los coches
- Media del tiempo de servicio requerido (tiempo que cada coche
desea permanecer aparcado)
- Media de los intervalos de tiempo que han transcurrido entre
la llegada de dos coches consecutivos
- Número total de coches atendidos
- Media del tiempo de espera antes de conseguir aparcar
- Media del tiempo de retorno normalizado
- Media del tamaño de la cola de espera
- Porcentaje de ocupación medio de la memoria
Para que en las estadísticas de cada algoritmo no influya la suerte,
en cada ejecución concreta llegarán los mismos coches, con idéntico
tiempo de servicio e intervalo de llegada entre ellos a cada una de
las cuatro aceras. Para el tiempo de servicio y el intervalo de llegada
entre coches, se usará una distribución exponencial. Para la longitud
de los coches, la distribución será uniforme, con una longitud mínima
de cuatro caracteres.
Parking acepta un máximo de dos argumentos por
la línea de órdenes. Si no se introducen argumentos, se imprimirá
un mensaje con la forma de uso del programa por el canal de
error estándar. En el caso de teclear un argumento, dicho argumento
será un número entero mayor o igual que cero
relacionado con la rapidez con que se producen los acontecimientos
en el programa. Cero indica la máxima rapidez y números
mayores suponen una rapidez progresivamente menor. Finalmente,
si son dos los parámetros introducidos, el primero es idéntico
al caso anterior y el segundo será una "D", indicando que se
desea que el programa produzca información de depuración por
el canal de errores estándar.
Para facilitar la tarea, tenéis a vuestra disposición
una biblioteca de funciones de enlazado dinámico
parking.dll y un fichero de cabeceras,
parking.h.
Gracias a la biblioteca, muchas de las funciones no las tendréis
que programar sino que invocarlas a la DLL, tal como se
explica en la sesión decimoquinta.
La biblioteca creará dos hilos adicionales a los vuestros para
su funcionamiento interno, de los cuales no tendréis que
ocuparos. Una descripción
detallada de las funciones de la biblioteca aparece más abajo
en esta misma página.
El programa, desde vuestro punto de vista, se simplifica
bastante. Se ha de llamar a la función inicio
de la DLL. El hilo dormirá 30 segundos e invocará a la función
fin, para acabar con la simulación. Cuando la
función fin retorne, se llamará a la función
poner_estadIsticas (nótese la I mayúscula) para
que se contrasten las estadísticas que habéis tomado con las
calculadas por la DLL. Ahí acabará el programa. Además, se programarán
cuatro funciones que serán llamadas por la DLL cada vez que
un coche llegue y cuatro funciones a las que la DLL llamará
cuando un coche tenga que marcharse. Dichas
funciones de rellamada son registradas en la función
inicio de la DLL.
Los prototipos de las dos tipo de funciones de rellamada,
se describen aquí:
int funciOn_llegada(int longitud, long t_serv,
long t_llegada, long delta_llegada, int color, unsigned long reloj);
La DLL llamará a una de estas funciones cuando llegue un nuevo
coche. La respuesta que debe devolver la codificación que
hagáis indicará qué se debe hacer con ese coche. -1 indica
que no hay sitio para él y debe encolarse. Un valor entre
0 y 79 significa la posición a partir de la cual se debe
aparcar el coche. Esta función también deberá crear un
nuevo hilo de ejecución para que aparque el coche con
ayuda de la función aparcar de la DLL.
La función, sin embargo, no debe esperar a que el hilo
recién creado acabe de aparcar el coche. Los parámetros
que la DLL pasa a la función son:
longitud: longitud del coche en caracteres.
t_serv: tiempo de servicio del coche.
t_llegada: tiempo de llegada del coche
al sistema (expresada en milisegundos).
delta_llegada: intervalo de tiempo transcurrido
desde que llegó el coche anterior hasta que llegó este.
color: color del coche.
reloj: valor actual del reloj de la
simulación.
void funciOn_salida(int posicion, int longitud,
long t_serv, long t_llegada, long delta_llegada, int color,
unsigned long reloj);
La función es llamada cuando ha expirado el tiempo de
aparcamiento de un coche. Al igual que ocurría con
la función anterior, se debe crear un nuevo hilo de ejecución
que saque al coche del aparcamiento, invocando a la función
desaparacar de la DLL. Tampoco esperará esta
función a que el hilo acabe. Los parámetros coinciden con los
de la función anterior, salvo:
posicion: posición (0-79) en la acera
donde se encuentra aparcado el coche que debe salir.
Características adicionales que programar
- El programa no debe consumir CPU apreciablemente
en los modos de retardo mayor o igual que 1.
para comprobar el consumo de CPU, podéis arrancar
el administrador de tareas de Windows NT, mediante
la pulsación de las teclas CTRL+ALT+SUPR.
Observad, no obstante, que en las aulas de informática
puede que esta opción esté deshabilitada.
- IMPORTANTE: Aunque no se indique
explícitamente en el enunciado, parece obvio que
se necesitarán objetos de sincronización en diferentes
partes del programa.
Biblioteca parking.dll
Con estra práctica se trata de que aprendáis a sincronizar y
comunicar hilos en WIN32. Su objetivo no es la programación.
Es por ello que se os suministra una biblioteca dinámica de
funciones ya programadas para tratar de que no tengáis que
preocuparos por la presentación por pantalla, la gestión de
estructuras de datos (colas, pilas, ...) , etc. También servirá
para que se detecten de un modo automático errores que se
produzcan en vuestro código. Para que vuestro programa funcione,
necesitáis la biblioteca parking.dll
y el fichero de cabeceras parking.h.
Ficheros necesarios:
Las funciones que la biblioteca exporta para que las uséis son:
BOOL inicio(TIPO_FUNCION_LLEGADA f_llegadas[],
TIPO_FUNCION_SALIDA f_salidas[],LONG intervalo, BOOL d)
El hilo principal debe llamar a esta función cuando desee
que la simulación comience. La función devuelve falso
si se ha producido un error. Los argumentos son:
f_llegadas: es un array de cuatro
elementos. Contiene los punteros a las funciones
de vuestro programa que queréis que la DLL invoque
cada vez que llega un coche nuevo para cada
algoritmo. El prototipo de
las funciones se ha especificado más arriba.
f_salidas: Lo mismo que el parámetro
anterior, pero para las funciones que son invocadas
cada vez que ha concluido el tiempo que debe permanecer
un coche aparcado y tiene que salir.
intervalo: equivalencia aproximada
del valor de un segundo de simulación en tiempo
real (expresada en milisegundos). Es el valor
que se ha pasado como primer argumento al programa.
d: flag que indica si se desea
que la biblioteca produzca información de
depuración por el canal de errores estándar.
void aparcar(int fila, int pos_final,
int longitud, long t_serv, lont t_llegada, long delta_llegada,
int color)
Se invoca esta función cuando queremos que aparezca por
la pantalla la animación de un coche aparcando:
fila: entero de cero a tres, correspondiente
con la acera donde se aparcará el coche.
pos_final: posición dentro de la acera (0-79)
donde se situará el extremo izquierdo del coche.
longitud: longitud del coche.
t_serv: tiempo de servicio en milisegundos.
t_llegada: tiempo que indicaba el reloj de
la simulación cuando el coche llegó (milisegundos).
delta_llegada: tiempo que ha transcurrido
desde que llegó el coche anterior (milisegundos).
color: color del coche.
void desaparcar(int fila, int pos_final,
int longitud, int color)
Idéntica a la función anterior, sólo que para que se muestre
la salida de un coche:
fila: Ídem aparcar.
pos_final: Ídem aparcar.
longitud: Ídem aparcar.
color: Ídem aparcar.
bool ocupado(int fila, int posicion)
Devuelve verdadero si la posición (0-79) de la fila (0-3)
indicadas en sus argumentos está ocupada por un coche.
bool fin(void)
Se debe llamar a esta función cuando se desee terminar la
simulación. Devolverá verdadero, si la simulación acabó por
un error.
void poner_estadIsticas(struct estadIsticas *estad_programa)
Esta función presenta un resumen con las estadísticas
calculadas por la DLL y las obtenidas por vuestro programa.
Se pasará un array de estructuras con las estadísticas
calculadas para cada algoritmo.
Se deben calcular todas salvo m_tamaNo_cola.
La struct estadIsticas está definida en
parking.h.
Sincronización interna de la DLL
La sincronización interna de la DLL está basada en un
mutex.
El esquema de sincronización interna es el siguiente:
Mutex Mu;
Mu=1;
[...]
Llegada de un coche:
===================
Wait(Mu);
Calcular la posición buena;
Imprimir información de depuración;
Llamada función rellamada usuario;
Comprobación de errores;
Marcar la zona de la acera como reservada;
ReleaseMutex(Mu);
Salida de un coche:
==================
Poner el coche más oscuro;
Wait(Mu);
Imprimir información de depuración;
Llamada función rellamada usuario;
Calcular estadísticas;
ReleaseMutex(Mu);
Función aparcar:
===============
Llevar el coche justo sobre la línea de donde tiene que aparcar
a falta de su último movimiento;
Wait(Mu);
Realizar el último movimiento;
Marcar como ocupada esa parte de la acera;
ReleaseMutex(Mu);
Función desaparcar:
==================
Comprobación de rango y existencia de coche;
Wait(Mu);
Sacar el coche del aparcamiento y poner sobre la línea;
Liberar esa parte de la acera;
ReleaseMutex(Mu);
Completar la salida del coche;