UTNianos

Versión completa: [Sistemas Operativos] Duda Ejercicio 7 Guía de Sincronización 2012
Actualmente estas viendo una versión simplificada de nuestro contenido. Ver la versión completa con el formato correcto.
Páginas: 1 2
Hola gente, paso mi resolución del ejercicio 7 de la guía de sincronización del 2012. Aguardo correcciones y comentarios. Muchas gracias!

7- Suponga que un proceso tiene por tarea compilar un conjunto de programas y luego enviar el
resultado de cada compilación por email al encargado de ese proyecto. Dicho proceso está
organizado de la siguiente manera: N hilos de kernel compilan cada uno un programa distinto, y
luego cada uno de ellos depositan en una lista (compartida para todo el proceso) el resultado,
por otro lado, un hilo de kernel retira los resultados de las compilaciones y manda un email por
cada uno de ellos.

Estructura compartida: lista // Lista de resultados de compilaciones

KLT compilador (N instancias)

While (TRUE){
id_programa = obtener_nuevo_programa();
r = compilar_programa(id_programa);
depositar_resultado(r, lista);
}

KLT notificador (1 instancia)

While (TRUE){
r2 = retirar_resultado(lista);
enviar_email(r2);
}

Asumiendo que la cantidad de programas a compilar es infinita, sincronice dicho código
mediante el uso de semáforos para lograr un correcto uso de los recursos bajo los siguientes
contextos:
a) Asumiendo que la lista no tiene límite de tamaño.
b) Asumiendo que la lista tiene un límite de M resultados como máximo.

a) int depositar = 1 ; int retirar = 0 ;

KLT compilador (N instancias)

While (TRUE){
id_programa = obtener_nuevo_programa();
r = compilar_programa(id_programa);
wait(depositar);
depositar_resultado(r, lista);
signal(retirar);
signal(depositar);
}

KLT notificador (1 instancia)

While (TRUE){
wait(retirar);
r2 = retirar_resultado(lista);
enviar_email(r2);
}
b) int depositar = 1 ; int retirar = 0 ; int resultados = M ;

KLT compilador (N instancias)

While (TRUE){
id_programa = obtener_nuevo_programa();
r = compilar_programa(id_programa);
wait(depositar);
depositar_resultado(r, lista);
wait(resultados);
signal(retirar);
signal(depositar);
}

KLT notificador (1 instancia)

While (TRUE){
wait(retirar);
r2 = retirar_resultado(lista);
signal(resultados);
enviar_email(r2);
}
Buenas, para mi no esta bien porque no aseguras mutua exclusión entre los procesos.

Me parece que tendrías que usar un mutex para encerrar las sentencias que usan recursos compartidos entre los procesos, porque cuando el Compilador hace el signal(resultado) habilita al Notificador a seguir su ejecución, pero el tema es que todos los procesos pueden entrar en su región critica al mismo tiempo y generar deadlock.
Hola, yo había pensado también en colocar un mutex en el Notificador, pasa que como dice que es una sola instancia, no consideré necesario aplicarle "exclusión mutua". Es decir, sólo me preocupe por evitar que se ejecute el Notificador cuando todavía no había ningún resultado depositado. Obviamente puedo estar equivocado, no lo se realmente.
El mutex lo usas en todos los procesos porque todos usan la lista (recurso compartido), sino cuando mandas la señal de que hay procesos en la lista no aseguras que uno solo pueda usar ese recurso en un momento dado.
Xavi82, ¿cómo quedaría entonces el código según vos? (Como para verlo más claramente).
alan2506, yo lo haría de la siguiente forma:
A cada línea que utilice un recurso compartido, le metes un wait y posteriormente un signal a un mutex. Con eso te aseguras que no entren en simultáneo a leer/escribir.

Luego tenes que asegurarte que el notificador, se ejecute únicamente después del compilador. Entonces al notificador le pones un wait(retirar) que comienza en 0 para que se ejecute únicamente cuando haya depositado (ahí pones el signal).

Espero haberte ayudado.
Saludos!

KLT compilador (N instancias)

int depositar = 1;
int retirar = 0;

While (TRUE){

id_programa = obtener_nuevo_programa();
r = compilar_programa(id_programa);

wait(depositar)
depositar_resultado(r, lista);
signal(retirar)
signal(depositar)

}

KLT notificador (1 instancia)

While (TRUE){

wait(retirar)
wait(depositar)
r2 = retirar_resultado(lista);
signal(depositar)

enviar_email(r2);

}
Julian, gracias por tu respuesta, entiendo lo que planteas.

Pasa que hay algo que no me termina de cerrar, porque en esta parte (ver código de color rojo), suponiendo que entiendo bien sincronización, me parece que estás eliminando la posibilidad de que en el KLT Compilador, los hilos depositen en la lista más de un elemento, es decir, no estás haciendo un buen uso de la lista. Lo que creo es que con ese mutex que pones en el KLT Notificador, estás forzando que en la lista haya sólo un elemento por vez, hasta que el KLT Notificador lo saque. Es decir, en tu lista va a haber un elemento o ninguno, y me parece que la idea es que en la lista haya N elementos, siempre y cuando se inserten y se retiren ordenadamente.

No se si estoy en lo correcto igual, lo más probable es que no...jaja

KLT notificador (1 instancia)

While (TRUE){

wait(retirar)
wait(depositar)
r2 = retirar_resultado(lista);
signal(depositar)


enviar_email(r2);

}
Yo lo hice así, a ver que te parece:

a)

estructura compartida: lista;
semaphore mutex s_mutex = 1, int s_cont = 0 ;

KLT compilador (N instancias)

While (TRUE){
id_programa = obtener_nuevo_programa();
r = compilar_programa(id_programa);
wait(s_mutex);
depositar_resultado(r, lista);
signal(s_mutex);
signal(s_cont);
}

KLT notificador (1 instancia)

While (TRUE){
wait(s_cont);
wait(s_mutex);
r2 = retirar_resultado(lista);
signal(s_mutex);
enviar_email(r2);
}


b) La diferencia con el anterior es que se inicializa s_cont a -M para ponerle limite a la cantidad de elementos en la lista.
Claro, qué boludo, lo único que estás impidiendo es que los procesos estén insertando elementos al mismo tiempo que se están retirando elementos. Esto no quiere decir, que por ejemplo venga una ráfaga de N hilos en el KLT Compilador, depositen N elementos en la lista, y después el KLT Notificador vaya sacando de a 1 esos N elementos. Es decir, la lista puede tener N elementos, a diferencia de lo que dije anteriormente.
xavi82, por qué en negativo? Hasta no completar los M elementos de la lista no estaría enviando mails, y si te quedan menos que M, quedarían bloqueados sin enviarse. Sería correcto?
Julián, al igual que vos, yo tengo entendido que en los semáforos contadores, la variable se inicia con el valor máximo de instancias disponibles. Por ejemplo, tengo 3 impresoras, mi variable va a ser int imp = 3;
El problema de iniciar con M el semáforo contador es que al ejecutar el signal(s_cont) el proceso Compilador ya te pasas del límite pedido, entonces para evitar esto lo inicializas negativo; lo que estaría contando en este caso serian lugares vacíos en la lista.

juliahn, no es correcto que no se envíen mails hasta que se llene la lista, si te fijas la implementación del signal en el Stallings dice que si el valor del semáforo es <= 0 luego de incrementar el mismo, saca un proceso de la cola de bloqueados y lo pone en listos, entonces el proceso Compilador cada vez que meta un resultado en la lista y haga el signal, habilita a un proceso bloqueado en el semaforo para que procese un elemento de la lista.

Espero se entienda algo.
Ojo con esto... Los semaforos nunca se inicializan en negativo. Un semaforo en -N quiere decir que hay N elementos encolados bloqueados.
Gracias Adriano por la corrección, ¿entonces como pones el límite a la lista? ¿Estaría correcto como lo hizo alan2506 en el primer post?
Esta bien encarada la idea de "lugares libres = M" y "mensajes depositados = 0" pero le faltan un par de cosas (los mutex que mencionaban y demas).
Páginas: 1 2
URLs de referencia