Sie sind auf Seite 1von 33

COMUNICACIÓN ENTRE PROCESOS Pág.

COMUNICACIÓN ENTRE PROCESOS

Los procesos requieren, con frecuencia, comunicarse entre sí. Es necesario


implementarla en forma estructurada sin utilizar interrupciones.

1. CONDICIONES DE COMPETENCIA

En algunos S.O. los procesos que trabajan juntos comparten, con frecuencia, un
espacio común para almacenamiento en el que cada uno puede leer o escribir. El
espacio compartido puede estar en memoria principal o puede tratarse de una
archivo compartido.

Por ejemplo: cuando un proceso desea imprimir un archivo, escribe el nombre


del mismo en un Directorio Spooler . Otro proceso, el Demonio para Impresión,
verifica periódicamente si existen archivos por imprimir y, en caso afirmativo, los
imprime. Una vez hecho esto, elimina el nombre del archivo del Directorio Spooler.

Supongamos que el Directorio Spooler tiene un gran número de entradas,


numeradas 0, 1, 2, ...... cada una de las cuales puede almacenar el nombre de una
archivo.

Imaginemos también que existen 2 variables compartidas:

Out: apunta hacia el siguiente archivo por imprimir


In: apunta hacia la siguiente entrada libre dentro del directorio.

Estas 2 variables pueden conservarse en un archivo de 2 palabras, disponible


para todos los procesos. En cierto instante las entradas 0, 1 y 2 están libres porque
ya se imprimieron y las entradas del 4 al 6 están ocupadas con los nombres de los
archivos que esperan ser impresos.

Cuando A vuelve a ejecutarse, revisa la variable Next-free-slot , encuentra el


valor 7 y escribe el nombre de su archivo en la entrada 7, luego incrementa Next-
free-slot y copia su valor a In (8).
COMUNICACIÓN ENTRE PROCESOS Pág. 2

El Directorio Spooler presenta consistencia interna, por lo que el Demonio para


impresión no observará nada. Sin embargo, el proceso B nunca imprimirá su
archivo.
Las situaciones como ésta, en que 2 o más procesos leen o escriben en ciertos
datos compartidos, y el resultado final depende de quién ejecuta qué cosa y en qué
momento, reciben el nombre de CONDICIONES DE COMPETENCIA.
Los resultados de la mayoría de las pruebas de ejecución son buenas, pero
ocasionalmente pueden ocurrir situaciones como la descripta.
Out: apunta hacia el siguiente archivo por imprimir
In: apunta hacia la siguiente entrada libre dentro del directorio.

Supongamos que en el mismo


momento los procesos A y B
requieren colocar un archivo en
la cola de impresión.
1
Podría ocurrir lo siguiente: A lee
2 In y almacena su valor (7) en una
variable local llamada Netxt-free-
3 slot. En ese momento ocurre una
Out = 4 interrupción de reloj y la CPU
4 decide que A ya obtuvo su
A
arch a tiempo de CPU y que ahora debe
5
ejecutarse B.
prog c
B también lee In y también
6
In = 7 obtiene el valor 7, por lo que
prog n
almacena dicho valor en la
B 7
. variable Next-free slot, escribe el
.
nombre de su archivo en la
.
. entrada 7, incrementa Next-free
.
-slot en 1, copia este valor en In
.
. (8) y sale.
.
.
COMUNICACIÓN ENTRE PROCESOS Pág. 3

2. SECCIONES CRÍTICAS

¿Cómo evitar las condiciones de competencia? La clave para evitar los


problemas en ésta y otras situaciones relacionadas con recursos compartidos es
determinar la forma en que más de un proceso lea o escriba los datos compartidos a
la vez es la EXCLUSIÓN MUTUA. Es decir, se debe garantizar que, si un proceso
utiliza un recurso compartido los demás procesos no puedan utilizarlo.
La dificultad planteada en el ejemplo tratado se debió a que el proceso B
comenzó a utilizar una de las variables compartidas (In) antes de que el proceso A
terminara de utilizarla.
La elección de Operaciones Primitivas Compartidas con el fin de lograr la
Exclusión Mutua es uno de los temas centrales del diseño en cualquier Sistema
Operativo.
En ciertos instantes los procesos están ejecutando cálculos internos y otras
tareas que NO CONDUCEN a Condiciones de Competencia.
Sin embargo, en algunas ocasiones el proceso puede requerir operar o acceder
a recursos compartidos que pueden llevar a conflictos. Esa parte del programa, en la
cual se accede a la memoria compartida, se denomina SECCION CRITICA.
Si se pueden organizar las cosas de forma que no suceda que 2 procesos
entren al mismo tiempo tiempo en su SECCIÓN CRITICA, podrán evitarse las
Condiciones de Competencia .
Aunque esta condición evita los conflictos, para que los procesos paralelos
cooperen en forma correcta y usen eficazmente los datos compartidos. Es necesario
que se cumplan 4 condiciones para poder obtener una buena solución:
1 - Dos procesos no deben encontrarse, al mismo tiempo, en su Sección Crítica.
2 - No deben hacerse hipótesis sobre la velocidad o el número de CPU´s.
3 - Ninguno de los procesos que se están ejecutando fuera de su Sección Crítica
puede bloquear a otros procesos.
4 - Ningún proceso debe esperar eternamente para entrar en su Sección Crítica.
COMUNICACIÓN ENTRE PROCESOS Pág. 4

3. MÉTODOS PARA LOGRAR LA EXCLUSIÓN MUTUA

3.1. Desactivación de Interrupciones


La solución más simple sería permitir a cada proceso que desactive las
interrupciones antes de entrar a su Sección Crítica. De esta forma la CPU no seía
interrumpida para alternar entre procesos.
Pero esto pone en riesgo el aspecto de SEGURIDAD ya que podría ocurrir que
un proceso se adueñe de la CPU al no activar nunca más las interrupciones.
Esta solución es aconsejable a modo núcleo (para que el S.O. no sea
interrumpido mientras está actualizando un PCB, por ejemplo), pero no en modo
usuario.

3.2. Variables de Cerradura


3.2.1. Alternancia Estricta
Se trata de una solución por SW, para ello se implementa una única variable de
cerradura. Si un proceso desea entrar en su Sección Crítica, primero debe
comprobar el valor de la cerradura (cada proceso tiene asignado un valor de
cerradura). Si el valor es el asignado al proceso, el mismo la incrementa y entra en
su Sección Crítica. Si el valor es distinto al que tiene asignado, el proceso debe
esperar.
Veamos un ejemplo para 2 procesos:
COMUNICACIÓN ENTRE PROCESOS Pág. 5

Sección No Crítica

Debe ejecutar su Sección


Crítica

NO SI
Proceso A
Turn=
0

Sección Crítica

Turn = 1

Sección No Crítica

Debe ejecutar su Sección


Crítica

Proceso B

NO SI
Turn=
1

Sección Crítica

Turn = 0
COMUNICACIÓN ENTRE PROCESOS Pág. 6

While (TRUE) { While (TRUE) {


while (turn!=0) / *wait* /; while (turn!=1) / *wait* /;
Critical section; Critical section;
Turn=1; Turn=0;
Non-critical-section; Non-critical-section;
} }

A B

El proceso A verifica el valor de turn. Si es 0 entra en su Sección Crítica. Cuando


sale de ella pone turn a 1 y entra a su Sección No Crítica.
El proceso B verifica el valor de turn. Si es 1 entra en su Sección Crítica.
Cuando sale pone turn a 0 y entra a su Sección No Crítica.
El procedimiento consiste en una espera ocupada, pues el proceso
constantemente pregunta por el valor de turn, desperdiciando tiempo de CPU.

Sin embargo, esta solución no es óptima. Supongamos la siguiente situación:


1) A sale de su Sección Crítica y pone turn a 1.
2) B entra en su Sección Crítica, termina rápidamente, pone turn a 0 y sale.
3) Ahora A entra en su Sección Crítica, termina muy rápidamente, pone turn a 1
y sale.
4) En este punto A y B están en su Sección No Crítica. Supongamos que A
termina antes que B y desea entrar en su Sección Crítica. No podrá hacerlo
porque B está demorada y turn = 1. Esto provoca el incumplimiento de la
Regla Nº 3 (Un proceso que está en su Sección No Crítica no debe bloquear
a otros procesos)
Esta solución requiere que los dos procesos alternen en forma estricta su
entrada en las regiones cíticas respectivas. Ninguno puede entrar 2 veces seguidas.
Aunque este algoritmo elimina conflictos, no es la mejor solución.
COMUNICACIÓN ENTRE PROCESOS Pág. 7

3.2.2. Solución de Peterson


Los procesos compartes 2 variables bandera(i) y turn
Var: bandera: array(0....1) of boolean;
turn:0...1;
Inicialmente bandera(0)=bandera(1)=false y el valor de turn es indiferente (0 o 1).
La estructura del proceso Pi es:

repeat

bandera(i) := cierto;
turn := j;
while (bandera(j) and turn=j) do

skip;

Seccion critica

bandera(i) := falso;

Para entrar a la seccion critica, primero pongo bandera(i) en cierto, y decimos


que es el turn del otro proceso que entre si lo desea (turn=j). Si ambos procesos
tratan de entrar al mismo tiempo, turn estara en ambos puestos en i y j
aproximadamente en el mismo momento. Pero solo una de estas aseveraciones
quedara: la ultima; pues la anterior sera sobre-escrita. El valor eventual de turn
decide cual de los 2 procesos podra entrar a su seccion critica primero.

Ahora probaremos que la solucion de Peterson es correcta. Para ello es


necesario demostrar que el requerimiento (a) -exclusion mutua- se preserva, que
(b) -progresion- se satisface y que (c) -espera limitada- tambien se cumple.
(a) Vemos que cada proceso Pi entra a su seccion critica solo si bandera(j)= falso
o turn=i. Tambien si ambos procesos requieren ejecucion en sus secciones criticas
al mismo tiempo, entonces bandera(0)=bandera(1)=cierto. Estas 2 observaciones
COMUNICACIÓN ENTRE PROCESOS Pág. 8

implican que P0 y P1 no pueden ejecutar con exito sus instrucciones while al


mismo tiempo, ya que el valor de turn puede ser 0 o 1, pero no ambos a la vez. Por
ende, uno de los procesos, por ejemplo Pj, debe haber ejecutado su while, mientras
que Pi tuvo que haber al menos ejecutado una sentencia adicional "turn=j". Sin
embargo, ya que en este momento bandera(j)=cierto, y turn=i, y esta condicion
persistira en tanto Pj este en su seccion critica, significa como resultado que la
exclusion mutua se preserva.
Para probar los requerimientos (b) y (c), observemos que un proceso Pi puede
prevenirse de entrar a su seccion critica solo si queda en loop en la sentencia while
con la condicion bandera(j)=cierto y turn=j: esta es la unica condicion de loop. Si Pj
no esta interesado en entrar a su seccion critica, entonces la bandera(j)=falso y Pi
puede entrar a su seccion critica.
Si Pj tiene bandera(j)=cierto y tambien esta ejecutando su sentencia while,
entonces turn es igual a j o a i. Si turn=i, Pi entra a su seccion critica y si turn=j, sera
Pj quien lo haga. Sin embargo, una vez que Pj salga de la misma, pondra en falso
bandera(j), permitiendo que Pi entre a su seccion critica. Si Pj pone
bandera(j)=cierto, tambion debe poner turn=i. Asi, como Pi no puede cambiar el valor
de la variable turn mientras ejecuta su sentencia while, Pi entrara a su seccion
critica (progresion) luego de al menos una entrada de Pj (espera limitada).
COMUNICACIÓN ENTRE PROCESOS Pág. 9

Modelo en bloque de la solución de Peterson

P0
SECCIÓN
NO CRÍTICA Continúa en la Sección No
crítica, en la instrucción
siguiente a la que llamó a la
Sección Crítica
Desea entrar a su
Sección Crítica

Señal 0 := V Indica que tiene intención de entrar a


Turn := 1 su SC y asigna el próximo turno a P1

Si Señal1 también es V y es el turno


de P1, entonces P0 debe esperar.

Si Señal1 es V pero es el turno de P0,


Señal 1 := V P0 entra a su SC.
SI NO
y
Turn := 1
Si Señal1 es F significa que P1 no
desea entrar a su SC. En ese caso,
aunque el turno corresponda a P1, P0
entrará a su SC

P0 ENTRA
EN SU SC

Señal 0 := F
COMUNICACIÓN ENTRE PROCESOS Pág. 10

Instrucciones Especiales de Máquina


Instrucción TSL
Esta propuesta requiere algo de ayuda del HW. Muchas computadoras,
principalmente las diseñadas teniendo en mente varios procesadores, disponen de
una instrucción TEST AND SET LOCK (TSL) que funciona como se explica a
continuación: Lee el contenido de una palabra de memoria en un registro, para
después almacenar un valor distinto de 0 en esa dirección de memoria. Las
operaciones de lectura y almacenamiento de la palabra tienen la garantía de ser
indivisibles, ninguno de los demás procesadores tiene acceso a la palabra hasta
terminar la instrucción. La CPU que ejecuta la instrucción TSL cierra el bus de
memoria para prohibir a las demás CPU el acceso a la memoria hasta terminar.
Para utilizar la instrucción TSL , se emplea una variable compartida bandera , la
cual coordina el acceso a la memoria compartida. Cuando bandera=0 cualquier
proceso puede darle el valor 1 mediante la instrucción TSL y luego leer o escribir en
la memoria compartida. Al terminar, el proceso hace bandera=0 mediante una
instrucción MOVE.
COMUNICACIÓN ENTRE PROCESOS Pág. 11

Sección No Crítica
Desea entrar a su
Sección Crítica

Preservar el valor de
bandera
(reg:=bandera)

Bandera = 1 Continúa en la Sección No


crítica, en la instrucción
siguiente a la que llamó a la
Sección Crítica

NO
SI
reg=0

Sección Crítica

Abandona Sección Critica.


Bandera = 0
COMUNICACIÓN ENTRE PROCESOS Pág. 12

Ventajas y Desventajas de las Instrucciones especiales de máquina

Ventajas
• Son aplicables a cualquier número de procesos
• Simple y fácil de verificar
• Puede usarse para designar varias Secciones Críticas. Cada Sección Crítica
puede definirse con su propia variable

Desventajas
• Se emplea espera activa
• Puede producirse inanición: cuando un proceso abandona su Sección Crítica y
hay más de un proceso esperando, la selección es arbitraria. De esta manera
podría denegarse el acceso a algún proceso indefinidamente.
• Puede producirse interbloqueo: supongamos dos procesos P1 y P2, P2 con
prioridad mayor a P1.
 Se está ejecutando P1, que ejecuta la instrucción TSL.
 P1 es interrumpido por P2. Si P2 intenta ejecutar TSL se le negará el acceso
por el mecanismo de Exclusión mutua. P2 entra en estado de
espera activa.
 Como P2 tiene mayor prioridad que P1, P1 no será planificado sino hasta que
P2 termine.

CPU

Espera por: Asignada a:

P1 P2

Asignada a: Espera por:

Sección
Crítica
COMUNICACIÓN ENTRE PROCESOS Pág. 13

4. DORMIR Y DESPERTAR
Las soluciones vistas presentan el inconveniente de la espera ocupada. Lo que
hacen estas soluciones es lo siguiente: cuando un proceso desea entrar a su
sección crítica, verifica si está permitida la entrada. Si no, el proceso se queda
esperando hasta obtener el permiso.
Esto no sólo desperdicia tiempo de CPU, sino también puede presentar efectos
inesperados. Supongamos una computadora con 2 procesos, A y B, donde A tiene
mayor prioridad que B. Las reglas de planificación son tales que A se ejcuta siempre
que esté en estado de listo. Supongamos que B se está ejecutando en su Sección
Crítica. A entra a la cola de Listos para su ejecución. A comienza una espera
ocupada, pero como B nunca se planifica cuando A está en ejecución no tiene
oportunidad de salir de su Sección Crítica, por lo que A hace un ciclo infinito. Esta
situación se denomina, a veces, Problema de la Inversión de Prioridad.
Existen primitivas de comunicación entre procesos que bloquean a la CPU en
vez de desperdiciar su tiempo cuando no se les permite entrar en su Sección Crítica.
Las más sencillas son SLEEP y WAKEUP.
SLEEP es una Llamada al sistema que provoca el bloqueo del proceso que hizo
la llamada.
WAKEUP es una llamada que tiene un parámetro, el proceso por despertar.

El problema del Productor y el Consumidor


Dos procesos comparten un almacén (buffer) de tamaño fijo.
Uno de ellos, el Productor, coloca información en el buffer, mientras que el
Consumidor la obtiene de él.
El problema surge cuando el Productor desea colocar información en el buffer,
pero el mismo está lleno. Lo mismo ocurre con el consumidor, cuando desea tomar
información del buffer y el mismo está lleno.
La solución es la siguiente: se define una variable count. Si N es el número de
elementos que caben en el buffer, el código del productor debe verificar si count=N.
En caso afirmativo el productor se irá a dormir, en caso contrario el productor
agregará un elemento e incrementará count.
COMUNICACIÓN ENTRE PROCESOS Pág. 14

El código del consumidor verificará si count=0. En caso afirmativo se irá a


dormir. En caso contrario leerá un elemento y decrementará count.
Cada uno de los procesos verifica si el otro debiera estar durmiendo. Si no
debiera, lo despierta (al final del código del productor pregunta si N=1, en ese caso
despierta al consumidor; al final del código del consumidor pregunta si count=N-1, en
tal caso despierta al productor).
¿Problemas? También se pueden dar Condiciones de Competencia. Podría
ocurrir que el Consumidor lea count=0 (buffer vacío). En ese momento, la CPU
alterna con el proceso Productor. El Productor agrega un elemento al buffer, lo
incrementa y como count=1 despierta al consumidor (que no está durmiendo) por lo
que WAKEUP se pierde.
Cuando se ejecuta el Consumidor verificará la variable count=0 (que leyóa
antes) y se irá a dormir, pero NUNCA SERÁ DESPERTADO. Tarde o temprano el
buffer se llenará, por lo que el Productor también se irá a dormir Y AMBOS
DORMIRÁN POR TODA LA ETERNIDAD.
Posible solución: agregar un bit de espera de despertar. Cuando se intenta
despertar a un proceso despierto el bit se activa (=1). Cuando el proceso intente ir a
dormir, primero verificará el valor del bit, si está activo lo desactiva (=0) y continúa
despierto.
Esta solución funciona así para 2 procesos. Si hay más de 2 procesos deberán
agregarse más bits.
COMUNICACIÓN ENTRE PROCESOS Pág. 15

Continúa con el
Continúa con el código del
código del Consumidor
PRODUCTOR Productor CONSUMIDOR

Desea entrar a la SC

SI NO
SI NO
Coun Coun
t=N t=0

SLEEP Agregar elto al Leer 1 elto del


SLEEP
buffer buffer

Count=count-1
Count=count+1

SI NO SI NO
Count Count
=1 =N-1

WAKEUP WAKEUP
Consumidor Productor
COMUNICACIÓN ENTRE PROCESOS Pág. 16

5. SEMÁFOROS

Para solucionar el problema del despertar perdido Dijkstra propuso el uso de una
variable entera para contar el número de despertares almacenados para su uso
posterior.
Presentó un nuevo tipo de variable llamada semáforo.

semáforo=0 no existen despertares almacenados


Si
semáforo > 0 están pendientes uno o más despertares.

Propuso dos operaciones:

DOWN: verifica si semáforo > 0 . En ese caso decrementa el valor del semáforo y
continúa (utiliza un despertar almacenado).
Si semáforo=0 el proceso se va a dormir.
La verificación del valor del semáforo y la acción de irse a dormir se realiza
en conjunto, como una única acción atómica e indivisible, lo que garantiza
que al momento de iniciar un proceso con un semáforo, ningún otro proceso
tiene acceso al semáforo hasta que la acción termine o se bloquee.

UP: incrementa el valor del semáforo correspondiente. Si uno o más procesos


dormían en ese semáforo y no podían completar la operación DOWN
anterior, el sistema elige uno de los procesos dormidos y le permite
ejecutar el DOWN
SEMAFOROS
Para solucionar el Problema del productor y el Consumidor mediante el uso de
semáforos se utilizan 3 semáforos:
• full: cuenta el número de entradas
Inicialización de ocupadas
constantesenyelvariables
buffer. Valor de inicio = 0.
• empty :cuenta el número de entradas N :=vacías
n en el buffer. Valor de inicio = N.
mutex := 1; empty := N; full := 0
• mutex se utiliza para garantizar la exclusión mutua. Valor de inicio = 1.

Procedimiento Productor

Procedimiento Consumidor
COMUNICACIÓN ENTRE PROCESOS Pág. 17

Procedimiento Productor
El proceso se bloquea y se
agrega a la cola de procesos
dormidos en empty
Produce_item

NO

DOWN (empty)

SI
DOWN (mutex)
empty <> 0

Agregar_item

UP (mutex)

UP (full)

Incrementa full y despierta uno de los


procesos dormidos en full (si los hubiera)
COMUNICACIÓN ENTRE PROCESOS Pág. 18

El proceso se bloquea y se
agrega a la cola de procesos
dormidos en full

Procedimiento Consumidor
NO

DOWN (full)
SI

full < 0
DOWN (mutex)

Leer_item

UP (mutex)

Incrementa empty y despierta uno de


UP (empty) los procesos dormidos en empty (si los
hubiera)

Consumir_item

OBSERVACIÓN:
Si en el código del productor en lugar de hacer DOWN empty primero y DOWN
mutex después, se invierte el orden podría ocurrir lo siguiente:
1. Un proceso entra a su SC mediante DOWN mutex
2. Luego ejecuta DOWN empty y debe irse a dormir porque empty era 0
3. Se ejecuta el Consumidor que, al encontrar mutex=0 se va a dormir. Ambos
procesos dormirán por siempre.
COMUNICACIÓN ENTRE PROCESOS Pág. 19

CONTADORES DE EVENTOS

La solución al problema del Productor y el Consumidor mediante semáforos se basa


en el concepto de EXCLUSIÓN MUTUA.
Es posible programar una solución sin EXCLUSIÓN MUTUA. Para ello se utilizan los
CONTADORES DE EVENTOS (E).
Se definen 3 operaciones sobre E (aunque no siempre se utilizan todas las
operaciones):

1. Read (E): regresa el valor actual de E


2. Advance (E): incrementa E en 1
3. Await (E,v): espera hasta que E sea >= v

Los Contadores de Eventos siempre se incrementan y siempre inicializan en 0.

En el caso de los Productores y Consumidores se utilizan 2 contadores de eventos:

In: cuenta el nº de elementos que el Productor ha colocado en el buffer.


Out: cuenta el nº de elementos que el Consumidor ha retirado del buffer.

Buffer >= in >= out

Inicialmente in = 0 y out = 0

Contador de Eventos

N := n
in:=0
out:= 0

Procedimiento Productor

Procedimiento Consumidor
COMUNICACIÓN ENTRE PROCESOS Pág. 20

Procedimiento Productor

seq := 0

Produce elemento

Cuenta los elementos producidos hasta el


seq = seq + 1 momento

NO

Await (out, seq – N)

SI

out >= seq - N


Agrega elemento al
buffer

Advance (in) Verifica si existe espacio en el buffer para


colocar el elemento.
Inicialmente seq-N será negativo (ej.= 1-20=
-19)
por lo que el Productor se ejecuta
Si el Productor genera N+1 elementos antes de
que el Consumidor inicie su ejecución, el
enunciado AWAIT esperará hasta que out = 1,
lo que ocurre sólo cuando el Consumidor retira
un elemento.
COMUNICACIÓN ENTRE PROCESOS Pág. 21

Procedim.Consumidor

seq := 0

Cuenta los elementos eliminados hasta el


seq = seq + 1 momento

NO

Await (in, seq )

SI

in >= seq
Retira elemento al
buffer

Advance (out)
Antes de intentar eliminar un elemento
verifica que existan elementos en el buffer.

Si:

Seq = 2 e In= 1 el Consumidor va a retirar un


2º elemento que aún no fue colocado en el
buffer
COMUNICACIÓN ENTRE PROCESOS Pág. 22

MONITORES

Tienen una propiedad importante que los hace muy útiles para implementar la
exclusión mutua: sólo uno de los procesos puede estar activo en el monitor a la vez.
Los monitores son concepto del lenguaje de programación. Los compiladores de los
lenguajes que los incorporan los reconocen y no permiten que un proceso entre al
monitor si existe otro en él, garantizando de esta forma la EXCLUSIÓN MUTUA.

Cuando un proceso llama a un procedimiento del monitor, las 1as instrucciones del
monitor verifican si hay otro proceso activo dentro del monitor. En caso afirmativo el
proceso que hace la llamada será suspendido hasta que otro proceso salga del
monitor.

Ejemplo

monitor Ejemplo
definición de variables enteras;
definición de variables de condición;

Procedimiento Productor;
..........................
..........................
.........................
fin Productor
Procedimiento Consumidor;
..........................
..........................
..........................
fin Consumidor;
fin monitor
COMUNICACIÓN ENTRE PROCESOS Pág. 23

La solución consiste en introducir variables de condición junto con 2 operaciones


sobre ellas, WAIT y SIGNAL.

Si un procedimiento de monitor encuentra que no puede continuar (ya sea porque el


productor encuentra el buffer lleno o el consumidor lo encuentra vacío) ejecuta un
WAIT en la variable de condición que corresponda (full o empty), lo cual provoca que
el proceso que hizo la llamada se bloquee y permite que unproceso que esté
esperando para entrar al monitor lo haga.

La señal SIGNAL sobre una variable de condición (full o empty) provoca que uno de
los procesos que duermen en esa variable se despierte y entre al monitor. Para ello,
el proceso que ejecutó SIGNAL debe salir del monitor. Esto implica que el enunciado
SIGNAL debe aparecer como último enunciado de un procedimiento de monitor.

Las variables de condición no acumulan señales para su uso posterior, lo que


significa que si ningún proceso duerme en la variable, la señal se pierde.

WAIT debe aparecer antes de SIGNAL.


COMUNICACIÓN ENTRE PROCESOS Pág. 24

Cola de entrada de Entrada


procesos

Datos Locales

Condic (x)

WAIT(x) Variables de Condición

Condic (y) Procedimiento i

WAIT(y)

Procedimiento j

Cola de Urgentes

SIGNAL Código inicialización

Salida

• Un proceso puede entrar al monitor llamando a cualquiera de sus


procedimientos.
• Los procesos que esperan a que se libere el monitor son colocados en una cola
de espera a la entrada.
• Una vez que el proceso está dentro del monitor puede suspenderse a sí mismo
temporalmente mediante WAIT. En tal caso se sitúa en una cola de procesos que
esperan volver a entrar en el monitor cuando la condición cambie.
COMUNICACIÓN ENTRE PROCESOS Pág. 25

• Si un proceso que se está ejecutando detecta con SIGNAL que una variable de
condición se ha modificado avisa de tal situación a la cola correspondiente.

MONITOR ProductorConsumidor

Definición de variables de condición y


variables enteras

Procedimiento agregar

Procedimiento leer

Desventajas del Monitor

1. Muy pocos lenguajes de programación incorporan monitores, a diferencia de los


semáforos que pueden incorporarse a cualquier lenguaje (incorporando a la
librería las rutinas en assembler )
2. Los monitores y los semáforos se diseñaron para resolver el problema de la
exclusión mutua en una o varias CPU que comparten memoria principal.
Cuando se dispone de un sistema distribuido, con varias CPU cada una con su
propia memoria unidas mediante una LAN, estas primitivas ya no sirven pues no
están previstas para el intercambio de información entre computadoras.
COMUNICACIÓN ENTRE PROCESOS Pág. 26

Procedimiento agregar

SI NO
count = N

WAIT (full) agregar_item

count := count + 1

SI
SIGNAL (empty) count = 1

NO

FIN
Procedimiento productor

Producir_item

ProductorConsumidor.agregar

NO SI
fin
FIN
COMUNICACIÓN ENTRE PROCESOS Pág. 27

Procedimiento leer

SI NO
count = 0

WAIT (empty) leer_item

count := count - 1

SI
SIGNAL (full) Count = N-1

NO

FIN
Procedimiento CONSUMIDOR

ProductorConsumidor.leer

Consumir_item

NO SI
fin
FIN
COMUNICACIÓN ENTRE PROCESOS Pág. 28

TRANSFERENCIA DE MENSAJES

Para el intercambio de información entre computadoras se utiliza la transferencia de


mensajes.

Se utilizan dos llamadas al sistema SEND y RECEIVE.

SEND (destinatario, mensaje)


RECEIVE (origen, mensaje)

Los sistemas con transferencia de mensaje tienen aspectos de diseño diferentes a


los vistos hasta ahora, especialmente si los procesos se encuentran en
computadoras diferentes en una red.

Sincronización
Desde el punto de vista de la sincronización pueden darse los siguientes casos:
1. Envío y Recepción bloqueante: el emisor y el receptor se bloquean hasta que
el mensaje llega a destino. En este caso existe fuerte sincronización.

2. Envío no bloqueante, Recepción bloqueante: el emisor puede continuar


enviando mensajes a otros procesos, en tanto el receptor se bloquea hasta que
llega el mensaje solicitado

3. Envío y Recepción no bloqueantes: nadie debe esperar.


COMUNICACIÓN ENTRE PROCESOS Pág. 29

El SEND no bloqueante es la forma más natural de esta primitiva. Un riesgo es que


el proceso genere mensajes repetidamente, usando tiempo de procesador. Además
carga sobre el programador el peso de determinar qué mensaje se ha recibido
(acuses de respuesta).
El RECEIVE es más natural que se implemente como bloqueante, ya que es natural
que un proceso que solicita cierta información requiera de ella para poder continuar.
Si el mensaje se pierde el proceso podría quedar bloqueado indefinidamente.

Si se implementa como no bloqueante podría suceder que el mensaje se envíe


después que el proceso ejecutó el correspondiente RECEIVE ( el mensaje se
perderá). Una forma de solucionar este inconveniente sería permitir al proceso
comprobar si hay un mensaje esperando antes de ejecutar un receive.

Otra forma de prevenir la pérdida de mensajes sería que el emisor y el receptor


convengan en que tan pronto se recibe el mensaje el receptor envíe un mensaje de
confirmación. Si transcurrido un tiempo el emisor no lo recibe, retransmite el
mensaje.

Podría suceder que el mensaje se recibe bien y lo que se pierde es la confirmación.


En este caso el emisor reenvía el mensaje, el cual llegará duplicado. En este caso
es importante identificar al mensaje con un nº de secuencia, así si el receptor
detecta dos mensajes con el mismo nº de secuencia, descartará uno

Direccionamiento

Directo

SEND incluye una identificación específica del proceso destino


RECEIVE el proceso designa explícitamente al proceso emisor.
COMUNICACIÓN ENTRE PROCESOS Pág. 30

Implícito
Se utiliza cuando no es posible conocer de antemano el proceso emisor, como es el
caso del proceso servidor de impresoras.
El parámetro origen tendrá un valor de retorno cuando se haya efectuado la
operación de recepción.

Indirecto
Los mensajes no se envían drectamente al emisor sino a una estructura de datos
compartida formada por colas que guardan mensajes temporalmente. Estas
estructuras de datos reciben el nombre de buzones.

E1 R1

BUZÓN

En Rn

Relación Muchos a muchos


E1

PUERTO R

En
Relación Muchos a uno

Útil para la interacción cliente-servidor, donde


un proceso ofrece un servicio a varios

R1

E BUZÓN

Rn

Relación uno a muchos

Un mensaje se envía a varios procesos


COMUNICACIÓN ENTRE PROCESOS Pág. 31

E BUZÓN R

Relación uno a uno

Enlace privado de comunicación entre 2 procesos

La asociación de procesos a buzones puede ser estática o dinámica.

• Los puertos suelen estar asociados estáticamente a algún proceso particular. El


puerto se crea y se asigna al proceso permanentemente. Lo mismo se aplica a la
relación uno a uno, que se define como una relación estática.
• Cuando hay varios emisores la asociación de un emisor a un buzón se hace
dinámicamente, mediante el uso de primitivas como conectar y desconectar.

Otro aspecto a considerar es la propiedad del buzón.

Puertos: son creados por el proceso receptor y se destruyen cuando dicho proceso
termina

Buzones: en este caso el S.O. puede ofrecer un servicio de creación de buzones. Si


los buzones son considerados como propiedad del proceso que los crea se
destruyen cuando el proceso creador termina.
Pueden ser considerados propiedad del S.O., en cuyo caso se necesita una orden
explícita para destruir el buzón.
COMUNICACIÓN ENTRE PROCESOS Pág. 32

Formato de mensajes

Origen

Destino

Longitud Cabecera
Inf. de control

Tipo

Contenido Cuerpo del


mensaje

Los mensajes pueden serd eformato FIJO para minimizar procesamiento y costo de
almacenamiento
Si se va a intercambiar una gran cantidad de datos, estos pueden ponerse en un
archivo y el mensaje hará referencia a este archivo.

Una solución más flexible es implementar mensajes de longitud variable.

Nombre de los procesos


Otro tema a considerar es el nombre de los procesos de manera que no exista
ambigüedad. Con frecuencia se utiliza un esquema del tipo proceso@maquina
Si no existe algún ente regulador podría suceder que dos máquinas tengan el mismo
nombre. Para ello se agrupa a las máquinas en dominios diferentes
proceso@maquina.dominio.

La autentificación es otro tema crucial. El cifrado de mensaje con clave es muy útil.
COMUNICACIÓN ENTRE PROCESOS Pág. 33

Exclusión mutua por medio de mensajes

RECEIVE bloqueante y SEND no bloqueante.

Un conjunto de procesos concurtrentes comparten un buzón exmut que puede ser


utilizado por todos los procesos para enviar y recibir.
Originalmente el buzón tiene un mensaje de contenido nulo.
1. Un proceso que desea entrar en su SC intenta recibir el mensaje. Si el buzón
está vacío el proceso se bloquea.
2. Una vez que el proceso consigue el mensaje ejecuta su SC y luego devuelve el
mensaje al buzón. De este modo el mensaje actúa como testigo (token) que se
pasa de un proceso a otro. Esta técnica supone que si hay más de un proceso
ejecutando la acción RECEIVE concurrentemente.
3. Si hay un mensaje se entrega sólo a uno de los procesos y los otros se bloquean.
4. Si el buzón está vacío todos los procesos se bloquean. Cuando haya un mensaje
disponible se activa y toma el mensaje uno de los procesos bloqueados.

Comenzar (*programa principal)


Programa ExclusionMutua
Crear_buzón
const n= nro. de procesos
Send (exmut, null);
Procedimiento P (i: entero);
Parbegin
var msj:mensaje;
P(1);
Comenzar
P(2);
Repetir
Receive (exmut,msj);
<Sección Crítica>
P(n)
send (exmut,msj)
Parend
<resto>
Fin
Fin

Das könnte Ihnen auch gefallen