Está en la página 1de 5

Nicolas De La Hoz Fernandez (201729392)

Juan Diego Martínez Camacho (201822347)

Documento de soporte

1. Propuesta de diseño

La clase ​Main es la clase principal del programa, que tiene como atributos los parámetros
generales de ejecución y el método main(). Se relaciona con un ​Buffer​, una lista de ​Servidor​, y
una lista de ​Cliente​.

La clase ​Buffer recibe, por medio de su constructor, un tamaño inicial asignado y la cantidad de
clientes que espera atender. Además, tiene un registro del tamaño actual (utilizado), un método
para añadir el mensaje dado como parámetro, un método para responder un mensaje, un
método para retirar un cliente, y un método para consultar la cantidad de clientes que faltan por
atender.

La clase ​Cliente​, que hereda de ​Thread​, recibe por su constructor un identificador, la referencia
a un ​Buffer​, y una lista de ​Mensaje​. Además, sobreescribe el método run().

La clase ​Mensaje recibe un número por su constructor, y tiene un método para aumentar el
número y otro para retornarlo.
La clase ​Servidor​, que también hereda de ​Thread,​ recibe por su constructor un identificador y
la referencia a un ​Buffer​. Además, sobreescribe también el método run().

Como bien se puede sobreentender, cada clase realiza las acciones del actor respectivo que
lleva su mismo nombre dentro del modelo propuesto en el caso. La única clase nueva añadida
fue la clase ​Main​, por motivos de estructura y facilidad de organización.

2. Funcionamiento del programa

● Funcionamiento global del sistema:

En el código main del programa, después de inicializar las variables globales del sistema
mediante un archivo (tamaño del buffer, cantidad de clientes, cantidad de servidores y mensajes
por cliente) este código en el main crea el buffer, todos los clientes con sus mensajes y todos
los servidores. Después le da start a todos los thread cliente y a todos los thread servidor. En
este momento el sistema debe desarrollarse de manera correcta pues cada cliente y cada
servidor sabe que tiene que hacer.

A continuación mostramos que hacen. El siguiente código es el método run de la clase ​Cliente​.

El código anterior hace lo siguiente. El cliente, por cada mensaje que tiene, guarda el número
que posee el mensaje y luego intenta añadirlo al buffer. Si no logra añadirlo se duerme. Una vez
lo logré revisa si le contestaron, si no se duerme. Cuando le contesten sigue con el siguiente
mensaje y si le contestan todos los mensajes termina, y le avisa al buffer que se retira. Es
importante notar que en el buffer se duermen todos los clientes y este mismo es el que les avisa
para despertar. Las escrituras en la consola se utilizan solo para revisar que el programa está
corriendo de manera correcta.

A continuación mostramos el código del método run de la clase ​Servidor​.


El servidor revisa constantemente, mediante una búsqueda semi-activa, por mensajes a
responder en el buffer, hasta el punto donde ya todos los clientes presupuestados para atender
se hayan atendido. En cada revisión hace yield, para dar espacio en el procesador pero quedar
listo para volver a correr. De esta manera los servidores contestan mensajes del buffer y
cuando no haya más clientes se apagan.

Esto nos muestra en general que hace el programa. Buffer simplemente guarda los mensajes
de los clientes y le permite a los servidores contestar los mensajes. A continuación mostramos
el detalle de lo que hace internamente buffer pues este es el responsable de la concurrencia del
programa y que esta no afecte el funcionamiento del mismo.

● Sincronización entre cada pareja de objetos que interactúan.

La concurrencia se da entre el buffer y el cliente y además entre el buffer y servidor. Mostramos


primero la interacción entre buffer y cliente. El siguiente fragmento de código es de la clase
Buffer​.

Este método permite al cliente añadir un mensaje al buffer. Notamos que el buffer revisa si está
lleno. Si lo está duerme al cliente y mientras esté lleno el cliente no va a poder avanzar. Si por
el contrario, hay espacio, el buffer añade el mensaje y suma uno a el tamaño actual del buffer.
Nótese que este método debe ser synchronized pues altera la variable que sabe el tamaño
actual del buffer y tiene también una comparación entre el tamaño actual del buffer y su tamaño
máximo. Lo último que notamos es que el buffer es el responsable de la sincronización del
método y de dormir al cliente (todo sucede sobre el objeto buffer).

La última relación de sincronización entre cliente y buffer es el siguiente fragmento de código de


la clase ​Cliente​:

En este fragmento de código dentro del método run, el cliente revisa si su mensaje fue
contestado. Si no fue contestado dentro de un synchronized donde el buffer es el monitor, el
buffer duerme al cliente hasta que sea despertado. Mientras no se conteste el mensaje del
cliente este volverá a dormir. Vemos de nuevo que el buffer es el responsable de la
sincronización y de dormir al cliente. Sin embargo, el cliente es responsable de saber si le
contestaron o no.

A continuación mostramos la interacción entre servidor y buffer. El siguiente fragmento de


código es de la clase ​Buffer​.

Este método de la clase de la clase buffer ayuda a un servidor a contestar un mensaje. El


método revisa si hay un mensaje en el buffer. Si lo hay entonces lo contesta (le suma al número
del mensaje), lo remueve del buffer, resta uno al tamaño actual del buffer, y le avisa a todos los
clientes que están dormidos que un mensaje fue contestado (recordamos los clientes son
responsables de saber si fue o no su mensaje). Este método debe ser sincronizado pues se
revisa si hay mensajes en el buffer, y puede que se elimine un mensaje del buffer y se cambie
la variable que sabe el tamaño actual del servidor. De nuevo el buffer es responsable de la
sincronización del método y de despertar a todos los clientes pues estos están dormidos en el.
Con esto tenemos ya las dos relaciones que pueden generar conflictos de concurrencia. Nos
damos cuenta que el buffer es el responsable de la concurrencia de todo el sistema. Es
importante que ambos métodos del buffer solo puedan ser ejecutados por un thread al tiempo
ya sea un cliente o un servidor pues están revisando y cambiando variables compartidas como
lo es el tamaño actual del buffer, los mensajes del buffer, y la cantidad de clientes por atender.
De esta manera logramos una funcionalidad correcta del programa.

También podría gustarte