Tema III (Sincronizacio€ ¢Ì’¡n de Procesos)

March 27, 2018 | Author: Jyah Joce Sanchez Coquecallata | Category: Process (Computing), Areas Of Computer Science, Concurrency (Computer Science), Software, Information Technology Management


Comments



Description

Sistemas Operativos (2010017) Tema III Comunicación y Sincronización de Procesos Los procesos que se ejecutan de forma concurrente en un sistema se pueden clasificar como procesos independientes o cooperantes. Un proceso independiente es aquel que ejecuta sin requerir la ayuda o cooperación de otros procesos. Los procesos son cooperantes cuando están diseñados para trabajar conjuntamente en alguna actividad, para lo que deben ser capaces de comunicarse e interactuar entre ellos. Tanto si los procesos son independientes como cooperantes, pueden producirse una serie de interacciones entre ellos. Estas interacciones pueden ser de dos tipos: • Interacciones motivadas porque los procesos comparten o compiten por el acceso a recursos físicos o lógicos. Por ejemplo, dos procesos totalmente independientes pueden competir por el acceso a disco, en este caso, el sistema operativo deberá encargarse de que los dos procesos accedan ordenadamente sin que se cree ningún conflicto. • Interacción motivada porque los procesos se comunican y sincronizan entre sí para alcanzar un objetivo común. Por ejemplo, un compilador se puede construir mediante dos procesos: el compilador propiamente dicho, que se encarga de generar código ensamblador, y el proceso ensamblador, que obtiene código en lenguaje máquina a partir del ensamblador. Estos dos tipos de interacciones obligan al sistema operativo a incluir mecanismos y servicios que permitan la comunicación y la sincronización entre procesos (IPC InterProcess Communication). 3.1 Condiciones de competencia. Muchos problemas se pueden resolver más fácilmente o más eficientemente si se usa procesos (o hebras) cooperativos, que se ejecutan concurrentemente, técnica que se conoce como programación concurrente. La programación concurrente es una herramienta poderosa, pero introduce algunos problemas que no existen en la programación secuencial (no concurrente). Suponiendo que se usan dos hebras concurrentes para determinar cuántos números primos hay en un intervalo dado. Siendo numPrimos una variable global, podemos ejecutar primos(1,5000) en paralelo con primos(5001,10000) para saber cuántos números primos hay entre 1 y 10000. ¿El problema? numPrimos es una variable compartida que se accesa concurrentemente, y puede quedar mal actualizada si se dan determinadas intercalaciones de las operaciones de las dos hebras. Para ejecutar una operación como numPrimos=numPrimos+1 se suelen requerir varias instrucciones de máquina, como ser: Suponiendo que, más o menos simultáneamente, las dos hebras encuentran su primer número primo. Podría darse el siguiente timing (inicialmente, numPrimos==0). Ing. Jorge Orellana A. 29 2 El problema de la sección crítica Éste es uno de los problemas que con mayor frecuencia aparece cuando se ejecutan procesos concurrentes tanto si son cooperantes como independientes. que sólo una hebra a la vez puede estar actualizando variables compartidas. o mejor dicho. pero lo correcto sería 2. de alguna manera. Esto se conoce como competencia por datos (data race. Ing. Cuando un proceso sale de la sección crítica debe indicarlo mediante otro fragmento de código. Si se considera un sistema compuesto por n procesos { P0. Este mecanismo debe proteger el código de la sección crítica y su funcionamiento básico es el siguiente: • • Cada proceso debe solicitar permiso para entrar en la sección crítica mediante algún fragmento de código. Los procesos que no quieren entrar no pueden formar parte de esta decisión. que se denomina salida de la sección crítica... . Además. La estructura general. ningún otro proceso lo podrá hacer. race condition) cuando el resultado depende del orden particular en que se intercalan las operaciones de procesos concurrentes. Espera acotada (Entrada garantizada -ausencia de inanición): debe haber un límite en el número de veces que se permite que los demás procesos entren a ejecutar código de la sección crítica después de que un proceso haya efectuado una solicitud de entrada y antes de que se conceda la suya. 30 . en el que cada uno tiene un fragmento de código. recursos compartidos. Pn }. ningún otro proceso puede ejecutar en su sección. la decisión de qué proceso entra en la sección se hará sobre los procesos que desean entrar. Este fragmento permitirá que otros procesos entren a ejecutar el código de la sección crítica. Para resolver el problema de la sección crítica es necesario utilizar algún mecanismo de sincronización que permita a los procesos cooperar entre ellos sin problemas. El problema se produce porque las dos hebras o procesos tratan de actualizar una variable compartida al mismo tiempo. Progreso (Ausencia de postergación innecesaria): si ningún proceso está ejecutando dentro de la sección crítica. de cualquier mecanismo que pretenda resolver el problema de la sección crítica es la siguiente: Entrada en la sección crítica Código de la sección crítica Salida de la sección crítica Cualquier solución que se utilice para resolver este problema debe cumplir los tres requisitos siguientes: • • Exclusión mutua: si un proceso está ejecutando código de la sección crítica. una hebra comienza a actualizarla cuando la otra no ha terminado. La cosa se resuelve si se garantiza. por tanto. o también. que se denomina sección crítica. • A continuación se examinan varias propuestas de solucion. Jorge Orellana A.Sistemas Operativos (2010017) El resultado es que numPrimos queda en 1. de manera que mientras un proceso esté ocupado actualizando la memoria compartida en su región crítica. 3. o en general. . en el que se accesa a variables comunes. que se denomina de forma genérica entrada en la sección crítica. La característica más importante de este sistema es que cuando un proceso se encuentra ejecutando código de la sección crítica. esta decisión debe realizarse en tiempo finito. ningún otro proceso pueda entrar en su región crítica y provocar algún problema. P1. primero examina la variable turno. 3. la CPU sólo se conmuta a otro proceso como resultado de una interrupción del reloj o de otro dispositivo. Tampoco funciona ya que si ambos procesos ponen interesado[i] en TRUE al mismo tiempo.Sistemas Operativos (2010017) 3. Si el turno está a 0. hasta que sea seguro entrar. Ing. Jorge Orellana A.2 Segundo intento (Variables de Bloqueo) Se considera una variable compartida (variable turno) cuyo valor es inicialmente 0. interesado[i] que está en verdadero si proceso i quiere entrar a la sección crítica y falso si no lo quiere. pondrá a 1 también el turno. un arreglo para los procesos interesados en ingresar a la seccion critica.2. ambos quedan esperando para siempre. y se tendrá a dos procesos en sus regiones críticas al mismo tiempo. y un 1 significa que algún proceso está en su región crítica. Suponiendo que un proceso lee el turno y observa que vale 0. 0 o 1.2. Esta llamada puede provocar su espera. puede examinar y actualizar la memoria compartida sin temor a intromisiones de otros procesos. verificar primero y setear despúes la variable interesado. Antes de utilizar las variables compartidas (es decir. si así lo desean. una vez que un proceso ha inhibido las interrupciones. el proceso lo pone a 1 y entra en la región crítica. Cuando termine de utilizar las variables compartidas. si es necesario. Además.1 Primer intento (Inhabilitación de interrupciones) La solución más sencilla es hacer que cada proceso inhiba todas las interrupciones nada más entrar en su región crítica y que las rehabilite nada más salir de ella. no puede ocurrir ninguna interrupción del reloj. Cuando un proceso quiere entrar en su región crítica. un proceso de usuario con capacidad de deshabilitar interrupciones puede colgar el sistema. se planifica otro proceso que pasa a ejecución y pone el turno a 1. Con las interrupciones inhibidas. Si el turno ya estaba a 1. Cuando el primer proceso se ejecute de nuevo.2. y con las interrupciones inhibidas la CPU no puede conmutarse a otro proceso. 3. Antes de que pueda poner el turno a 1.4 Cuarto intento (Solución de Peterson) Combinando las dos ideas anteriores se puede obtener un algoritmo que sí funciona. pero entonces se podría terminar con los dos procesos en la sección crítica. el proceso espera hasta que vuelva a valer 0. un 0 significa que ningún proceso está en la región crítica. antes de entrar en su región crítica). Se descarta por peligroso. 31 . no funcionaría en multiprocesadores. como parámetro. Después de todo. Entonces.3 Tercer intento (Alternancia Estricta) Otro intento de solucion permite manejar más información. Se podría cambiar el orden. Entonces. el proceso invoca abandonar_region para indicar que ha terminado y para permitir a los demás procesos entrar. cada proceso invoca entrar_en_region con su propio número de proceso.2. 3. 2. Ahora el proceso 0 llama a entrar_en_region.5 Solución con ayuda del hardware Muchos sistemas tienen instrucciones especiales que ayudan bastante a la hora de resolver el problema de la sección crítica. 32 . en el sentido que ningún otro proceso puede accesar esa dirección de memoria hasta que la instrucción se complete. TEST-AND-SET (TS) lee el contenido de una dirección de memoria en un registro. La asignación que va a prevalecer es la del último proceso que realice la asignación. Este protocolo provee exclusión mutua sin postergación innecesaria. quedará atrapado en esa función hasta que interesado[0] pase a valer FALSE. Jorge Orellana A. El proceso 1 se pone a dar vueltas en el bucle y no entra en su región crítica hasta que el proceso 0 sale de su región crítica. 3. Indica su interés poniendo a TRUE su componente del array interesado y pone el valor 0 en turno. Si el proceso 1 llama ahora a entrar_en_region. una solución al problema de la sección crítica. Ya que el proceso 1 no está interesado. de manera que turno es 1. Por ejemplo. el proceso 0 la ejecuta cero veces y entra en su región crítica. entrar_en_region retorna inmediatamente. sería: Inicialmente. y pone un 1 en la misma dirección. Ambos deben asignar su número de proceso a la variable turno. la variable lock está en 0. y sirve para n procesos.Sistemas Operativos (2010017) Inicialmente no hay ningún proceso en su región crítica. siendo anulada la primera de las asignaciones por la sobreescritura. todo en una sola acción atómica o indivisible. Supongamos que el proceso 1 es el último que hace la asignación. en pseudoasssembler. son instrucciones que de alguna manera combinan dos o tres operaciones en una sola operación atómica. Ing. Si se considera el caso en que ambos procesos llaman a entrar_en_region casi simultáneamente. Cuando ambos procesos entran en la sentencia while. En general. algo que sólo ocurre cuando el proceso 0 llama a abandonar_region para salir de la región crítica. pero puede haber inanición. De cierto modo es equivalente a: Con esto. o simplemente distintos. podría bloquear a un proceso que quiere entrar a la sección crítica. el sistema elige a uno de ellos (por ejemplo de forma aleatoria) y se le permite completar esa operación wait pendiente. La operación de incrementar el semáforo y despertar un proceso es también indivisible. La comprobación del valor del semáforo. sin concederle oportunidad de ejecutar. El problema de la sección crítica se puede resolver fácilmente con un semáforo S. A nivel de sincronizacion. Una posibilidad es usar semáforos. se realizan como una única acción atómica indivisible. cuando un proceso quiere entrar a la sección crítica. con valor inicial 1. La operación de signal nunca bloquea al proceso que la ejecuta. su modificación y la posible acción de dormirse. son que es difícil generalizarlas para problemas de sincronización más complejos. Un semáforo S es un tipo abstracto de dato que puede manipularse mediante dos operaciones: P (o wait o down) y V (o signal o up). Si uno o más procesos estuviesen dormidos sobre ese semáforo. y cuyo efecto es equivalente a: La operación wait sobre un semáforo comprueba si el valor es mayor que 0. el proceso procede a dormirse sin completar la operación bajar por el momento. Si el sistema operativo tuviera un mayor conocimiento de la situación. Está garantizado que una vez que comienza una operación sobre un semáforo. si se quiere que un proceso P2 ejecute un trozo de código C2 pero sólo después que P1 haya completado otro trozo C1. el semáforo sigue valiendo 0. ya que usan espera ocupada (busy waiting). ningún otro proceso puede acceder al semáforo hasta que la operación se completa o hasta que el proceso se bloquea.2. Si lo es. se usa un semáforo para sincronizar con valor inicial 0. 33 . simplemente decrementa el valor (es decir utiliza una de las señales guardadas). está permanentemente chequeando si puede hacerlo. después de ejecutarse un signal sobre un semáforo con procesos dormidos en él.Sistemas Operativos (2010017) 3. mientras no pueda entrar. Ing. Si el valor es 0. Entonces. dormido en él. Esta atomicidad es absolutamente esencial para resolver los problemas de sincronización y evitar que se produzcan condiciones de competencia. de la sección crítica y derrochan CPU. Jorge Orellana A. incapaces de completar una anterior operación de wait. pero habrá un proceso menos.6 Semáforos Los inconvenientes de las soluciones anteriores. La operación signal incrementa el valor del semáforo al cual se aplica. resulta mucho más difícil que se produzcan errores. Los monitores son una herramienta de sincronización más estructurada que encapsula variables compartidas en conjunto con los procedimientos para accesar esas variables.2. por lo que el compilador sabe que son especiales. lo pone al final de la cola asociada a c. pero siguen siendo de bajo nivel. Una variable de condición c tiene asociada una cola de procesos. Si ningún otro proceso está utilizando el monitor. nunca habrá dos procesos que ejecuten sus regiones críticas a la vez. y siempre están sujetas a errores como la omisión o mala ubicación de una operación wait o signal. Los monitores tienen una importante propiedad que los hace útiles para conseguir exclusión mutua: en cualquier instante solamente un proceso puede estar activo dentro del monitor. el proceso deja de estar activo dentro del monitor. O sea. el proceso que hizo la llamada debe suspenderse hasta que el otro proceso abandone el monitor. Un monitor es. cuando un proceso llama a un procedimiento de un monitor. y por lo tanto otro proceso puede ejecutar dentro del monitor. si es que existe. En ese caso. Debido a que es el compilador y no el programador el que organiza las cosas para conseguir la exclusión mutua. y por lo tanto: • Los procesos pueden llamar a los procedimientos del monitor en cualquier momento. las variables locales al procedimiento. aunque no se haya completado un procedimiento. y soporta dos operaciones: • wait(c): suspende al proceso invocador. 34 . La forma más común de implementarla es utilizando una variable de exclusión mutua o un semáforo binario. el proceso que hace signal continúa dentro Ing. pero no pueden accesar directamente las variables encapsuladas por el monitor.7. • Las variables permanentes del monitor deben estar inicializadas antes que ningún procedimiento sea ejecutado. un tipo de dato abstracto. en consecuencia. las primeras instrucciones del procedimiento comprueban si cualquier otro proceso está actualmente activo dentro del monitor.Sistemas Operativos (2010017) 3. de manera que puede tratar las llamadas a los procedimientos del monitor de forma diferente que a otras llamadas a procedimientos normales. • Los procedimientos dentro del monitor no pueden accesar variables externas al monitor: sólo pueden accesar las variables permanentes del monitor (i y c en el ejemplo). Corresponde al compilador implementar la exclusión mutua sobre las entradas al monitor. Es suficiente con que sepa que metiendo todas las regiones críticas en procedimientos del monitor. y libera el monitor. Las soluciones mediante semáforos no son ni muy limpias ni muy claras. Para esperar eventos (sincronización por condición) se usan variables de condición. Los monitores son construcciones del lenguaje. la persona que escribe el monitor no tiene que preocuparse de cómo consigue asegurar la exclusión mutua el compilador dentro del monitor. En cualquier caso. • signal(c): despierta al proceso al frente de la cola asociada a c. el proceso que hizo la llamada puede entrar inmediatamente. En monitores con semántica signal-and-continue. Jorge Orellana A. Monitores Los semáforos son una herramienta general y eficiente para sincronizar procesos. y los argumentos del procedimiento (x en el ejemplo). En la mayoría de los casos. 8. Entonces si una variable de condición recibe una señal sin que haya ningún proceso esperándola. ofrece dos procedimientos wait y notify que son los equivalentes de wait(c) y signal(c) salvo que cuando se utilizan dentro de métodos sincronizados no están expuestos a que se produzcan condiciones de competencia.Sistemas Operativos (2010017) del monitor. En el problema se describen dos procesos. si es necesario. el proceso puede ver si esa operación es necesaria. Algunos lenguajes de programación reales soportan los monitores. la señal se pierde para siempre. búffer fijo utilizado como una cola.3. pero si se quiere que los procesos intercambien información se tiene que agregar variables compartidas a la solución. aunque no siempre en la forma diseñada. el productor y el consumidor. Si no está disponible ningún mensaje. Añadiendo la palabra reservada synchronized a la declaración de un método. por ejemplo Java. Productor-consumidor con buffer limitado El problema del productor consumidor (también conocido como el problema de buffer acotado) es un ejemplo clásico de un problema de multi. El problema es asegurarse de que el Ing. 35 . La primera llamada envía un mensaje a un destinatario dado y la segunda recibe un mensaje de un remitente dado (o de cualquiera. ya que no acumulan las señales para un uso posterior como hacen los semáforos. 3. Se puede intercambiar información mediante paso de mensajes. Este método de comunicación entre procesos utiliza dos primitivas.2. inspeccionando esas variables. el proceso despertado. &mensaje). Como tales. es fácil seguir la pista del estado de cada proceso utilizando variables adicionales. El trabajo del productor es generar un conjunto de productos y colocarlos en el buffer (almacen). enviar y recibir. si al receptor no le importa el remitente). Al mismo tiempo.1. o no. En otras palabras el wait debe ocurrir antes que el signal. Los métodos sincronizados de Java difieren de los monitores clásicos en un aspecto esencial: Java no dispone de variables de condición. que comparten un común. De forma alternativa. 3. si existe.3. los retira del buffer) de una sola pieza a la vez. tales como enviar(destinatario. Las variables de condición no son contadores. puede retornar inmediatamente indicando un código de error. el receptor puede bloquearse hasta que llegue uno. el señalizador debe esperar (posiblemente compitiendo con otros procesos) para poder volver al monitor. Java es un lenguaje orientado a objetos que soporta threads a nivel de usuario y que permite agrupar juntos varios métodos (procedimientos) formando clases. recibir(remitente. pueden incluirse fácilmente en librerías de procedimientos. no se le permite a ningún otro thread comenzar a ejecutar cualquier otro método synchronized de esa clase. si es que el signal despierta a un proceso. Problemas clásicos de sincronización 3. &mensaje). Paso de mensajes Las primitivas vistas hasta ahora sirven para sincronizar procesos. que igual que los semáforos y de forma diferente a los monitores son llamadas al sistema en vez de construcciones del lenguaje de programación. En monitores con semántica signal-and-wait. Jorge Orellana A.proceso de sincronización. el consumidor consume los productos (es decir. y en la práctica no representa ningún problema ya que. En su lugar. debe esperar su oportunidad para volver a entrar al monitor y continuar después del wait. Antes de llevar a cabo un signal. Esta regla simplifica mucho la implementación. Un sistema de paso de mensajes bien conocido es MPI (Message-Passing Interface) que es una librería para lenguajes de programación como el C. El paso de mensajes se utiliza comúnmente en sistemas de programación paralela. entonces el proceso señalizador suspende su ejecución en favor del proceso señalizado. Java garantiza que una vez que un thread comienza a ejecutar ese método. El problema también puede ser generalizado para tener múltiples productores y consumidores... Jorge Orellana A. while(producto <= MAXPRODUCCION) { wait(semProductor). estadoConsumo = 1... como se muestra en el código siguiente: int cantProductos = 0. consumidor(1). //numero de elementos a producir int estadoConsumo = 0. usando semáforos. 36 . } } } void main() { cobegin { productor(1).En la cola de produccion estan: " << cantProductos << " productos\n\n".en la cola de produccion estan: " << cantProductos << " productos\n\n". p = colaProduccion[ultimo].. el productor produce y el consumidor deja de consumir void productor(int ID) { int producto = 1. signal(semBuffer). signal(semBuffer). lo duerme semaphore semConsumidor = 0. reciente = (reciente + 1) % tamBuffer. cout << ".1. } else { estadoConsumo = 0. semaphore semProductor = 1. producto = producto + 1. producto = producto + 1. } if((estadoProduccion == 0) && (estadoConsumo == 1)) { signal(semProductor). //tamaño buffer const int MAXPRODUCCION = 10. estadoProduccion = 1.. estadoConsumo = 1. // Si el buffer esta vacio.Sistemas Operativos (2010017) productor no intente agregar productos en el búffer si está lleno y que el consumidor no va a tratar de consumir productos de un búffer vacío. wait(semBuffer). } } } void consumidor(int ID) { int producto = 1. // controla la estricta alternancia. } } Ing. cantProductos = cantProductos + 1. ultimo = (ultimo + 1) % tamBuffer. estadoProduccion = 1. int estadoProduccion = 1. cout << "Consumidor " << ID << " consumio el producto " << p << endl. if(cantProductos > 0) { signal(semConsumidor). productor(2). consumidor(2). colaProduccion[reciente] = ID*100+producto. Si esta en 1 el consumidor consume // Si esta en 0. } if ((estadoConsumo == 0) && (estadoProduccion == 1)) { signal(semConsumidor). cout << "Productor " << ID << " produce el producto " << ID*100+producto << endl. int reciente = 0. } else { estadoProduccion = 0. wait(semBuffer). // cantidad de productos que se encuentran en el buffer const int tamBuffer = 5. lo duerme semaphore semBuffer = 1. La solución se puede alcanzar por medio de la comunicación entre procesos. cout << ". while(producto <= MAXPRODUCCION) { wait(semConsumidor). if(cantProductos < tamBuffer) { signal(semProductor). cantProductos = cantProductos . int ultimo = 0. // Si el buffer esta lleno. int p. int colaProduccion[tamBuffer]. for (I = 1.3. Lector-Escritor Un objeto. cout << N << " esta leyendo" << '\n'. else signalc(OKleer). //inicializacion } } // fin monitor void Lector(int N) { int I. 37 . cout << "Numero lectores concurrentes " << contadorLector << '\n'. La solución se puede alcanzar por medio de la comunicación entre procesos. void EmpiezaLeer() { if (ocupado || !empty(OKescribir)) waitc(OKleer). no puede haber ningún lector ni ningún otro escritor. pero cuando hay un proceso escribiendo. if (empty(OKleer)) signalc(OKescribir). es compartido por varios procesos concurrentes. que modifican el objeto. Hay procesos escritores.2. Puede haber múltiples procesos leyendo el objeto simultáneamente. } void EmpiezaEscribir() { if (ocupado || (contadorLector != 0)) waitc(OKescribir).1. // lectores concurrentes int ocupado. } void FinEscribir() { ocupado = 0. tal como un archivo o un registro de una base de datos. Ing. Jorge Orellana A.Sistemas Operativos (2010017) y su ejecucion sería: 3. condition OKleer. } void FinLeer() { contadorLector = contadorLector . signalc(OKleer). FinLeer(). } init { contadorLector = 0. ocupado = 1. I++) { EmpiezaLeer(). if (contadorLector == 0) signalc(OKescribir). I < 2. OKescribir. que sólo lo consultan. ocupado = 0. } } void Escritor(int N) { int I. usando monitores: monitor LectorEscritor { int contadorLector. contadorLector = contadorLector + 1. y procesos lectores. } } y su ejecucion sería: 3. pos[fil][1]. con resultados gráficos también: #include "gdefs. pos[fil][3]). Escritor(2). de los 5 filósofos. Escritor(1). FinEscribir(). Jorge Orellana A. int inc = 0. pos[fil][3]). I < 2.//condicion del cubierto de cada filósofo void comer(int fil){ if((estFil[fil]==HAM) && (estFil[(fil+4)%5]!=COM) && (estFil[(fil+1)%5]!=COM)){ estFil[fil] = COM. } } } void pensar(int fil){ if(estFil[fil]!=PEN){ //Filósofo Pensando cout<< "Filosofo pensando "<< fil <<endl. pero como son pobres. YELLOW. int HAM = 1. } } void mirar(int fil){ if(estFil[fil]==PEN){ estFil[fil] = HAM. pos[fil][1]. 38 . cout << N << " esta escribiendo" << '\n'. pos[fil][2]. } } init{ Ing. int i. estFil[fil] = PEN. create(fil. pos[fil][3]). TRIANGLE. TRIANGLE. GREEN.//estado de todos los filósofos condition libre[5]. alrededor de una mesa redonda. } } void main() { cobegin { Lector(1). Han acordado que cada uno usará sólo los tenedores a su izquierda y a su derecha. Los filósofos comensales Cinco filósofos pasan la vida alternando entre comer y pensar.3. Como son medio torpes.Sistemas Operativos (2010017) for (I = 1. int Mesa = 100. requieren dos tenedores para comer. if(estFil[fil] != COM){ //Filósofo Hambriento cout<< "Filosofo hambriento "<< fil <<endl. pos[fil][0]. pos[fil][0]. create(fil. sólo tienen 5 tenedores. int COM = 2. create(fil. Entonces. waitc(libre[fil]). y no pueden comer dos que son vecinos. monitor FilosofoComensal { int estFil[5]. TRIANGLE. int pos[5][4]. usando monitores. pos[fil][2]. comer ((fil+1)%5). pos[fil][0]. //Filósofo Comiendo cout << "Filosofo comiendo "<< fil <<endl. comer(fil). pos[fil][1]. comer ((fil+4)%5). I++) { EmpiezaEscribir(). pos[fil][2]. Lector(3). signalc(libre[fil]). sólo 2 pueden comer al mismo tiempo.cm" const int PEN = 0. RED. La solución se puede alcanzar por medio de la comunicación entre procesos. Lector(2).3. pos[0][3] = 30. filosofo(2). GREEN. while (inc < 100){// tiempo de vida de un filosofo if ((random(2))==PEN) pensar(fil). pos[0][2] = 30. WHITE. pos[1][2] = -30. pos[1][1] = 230.Sistemas Operativos (2010017) for(i = 0. i++){ estFil[i]=PEN. pos[2][0] = 245. 50). pos[4][2] = -30. filosofo(3). pos[3][0] = 305. 50. BLACK. Jorge Orellana A. } void main(){ create(Mesa. pos[fil][2]. pos[1][3] = -30. pos[fil][3]). 39 . pos[3][3] = 30. pos[1][0] = 230. pos[fil][0]. 250. cobegin{ filosofo(0). pos[2][3] = 30. pos[4][3] = -30. pos[4][1] = 230. CIRCLE. TRIANGLE. inc = inc + 1. //inicializacion } //Posiciones Graficas de los Filosofos pos[0][0] = 275. pos[3][1] = 245. filosofo(4). pos[fil][1]. pos[fil][3]). pos[fil][2]. pos[4][0] = 320. pos[3][2] = 30. } pensar(fil). pos[2][2] = 30. } } y su ejecucion sería: Ing. pos[fil][0]. i<= 4. 200. pos[fil][1]. else mirar(fil). pos[0][1] = 160. TRIANGLE. filosofo(1). //los filosofos se van create(fil. } } void filosofo(int fil){ create(fil. pos[2][1] = 245.
Copyright © 2024 DOKUMEN.SITE Inc.