Está en la página 1de 11

Taller de segundo corte

Steven Reales, Cristian Suarez

Docente:
YESITH TERNERA MUÑOZ

Trabajo:
Comunicación y Sincronización de Procesos

Universidad de la costa
Asignatura – Sistemas Operativos
2021-1
Introducción

En los sistemas operativos multiprogramados surge el concepto de proceso, asociado


a la ejecución de un programa. En general, un proceso es un flujo de ejecución,
representado básicamente por un contador de programa, y su contexto de ejecución,
que puede ser más o menos amplio. Así, un proceso incluye en su contexto el estado
de la pila, el estado de la memoria y el estado de la E/S, mientras que un thread típico
tiene como contexto propio poco más que la pila. En algunos sistemas es posible
determinar el contexto propio de un proceso en el momento de su creación, como ocurre
con la llamada al sistema clone () de Linux. En adelante, sin perder generalidad,
utilizaremos siempre el término proceso, independientemente de cuál sea su contexto.
Comunicación y Sincronización de procesos

1. La exclusión mutua es la actividad que realiza el sistema operativo para evitar que dos
o más procesos ingresen al mismo tiempo a un área de datos compartidos o accedan
a un mismo recurso.
En otras palabras, es la condición por la cual, de un conjunto de procesos, sólo uno puede
acceder a un recurso dado o realizar una función dada en un instante de tiempo.
En sistemas de multiprogramación con un único procesador, los procesos se intercalan en
el tiempo para dar la apariencia de ejecución simultánea.
Uno de los grandes problemas que nos podemos encontrar es que el hecho de compartir
recursos está lleno de riesgos.
Por ejemplo, si dos procesos hacen uso al mismo tiempo de una variable global y ambos
llevan a cabo tanto operaciones de lectura como de escritura sobre dicha variable, el
orden en que se ejecuten estas lecturas y escrituras es crítico, puesto que se verá
afectado el valor de la variable.
2. Semáforos
2.1 Concepto
Dijkstra dio en 1968 una solución elegante y sencilla al problema de la exclusión
mutua con la introducción del concepto de semáforo binario. Esta técnica permite
resolver la mayoría de los problemas de sincronización entre procesos y forma parte
del diseño de muchos sistemas operativos y de lenguajes de programación
concurrentes.
Un semáforo binario es un indicador de condición (S) que registra si un recurso está
disponible o no. Un semáforo binario sólo puede tomar dos valores: O y 1. Si, para un
semáforo binario. S=1 entonces el recurso está disponible y la tarea lo puede utilizar;
si S=0 el recurso no está disponible y el proceso debe esperar.
Los semáforos sólo permiten tres operaciones sobre ellos:
Espera.
Señal.
Inicializar.

1 wait (variable)
2 begin
3 while (variable)>=0 do {esperar}
4 variable=variable-1
5 end

1 signal (variable)
2 begin
3 variable=variable+1
4 end

El wait y el signal son indivisibles y no se pueden interrumpir, es decir, no se pueden


ejecutar ambas a la vez.
Los semáforos binarios los utilizaremos para recursos de una sola instancia, y para
sincronización binaria.
2.2 Semáforos generales

El semáforo binario resulta adecuado cuando hay que proteger un recurso que
pueden compartir varios procesos, pero cuando lo que hay que proteger es un
conjunto de recursos similares, se puede usar una versión más general del
concepto de semáforo que lleve la cuenta del número de recursos disponibles.

En este caso el semáforo se inicializa con el número total de recursos disponibles


(n) y las operaciones de espera y señal se diseñan de modo que se impida el
acceso al recurso protegido por el semáforo cuando el valor de éste es menor o
igual que cero.
Cada vez que se solicita y obtiene un recurso, el semáforo se decrementa y se
incrementa cuando se libera uno de ellos. Si la operación de espera se ejecuta
cuando el semáforo tiene un valor menor que uno, el proceso debe quedar en
espera de que la ejecución de una operación señal libere alguno de los recursos.

Al igual que en los semáforos binarios, la ejecución de las operaciones es


indivisibles, esto es, una vez que se ha empezado la ejecución de uno de estos
procedimientos se continuará hasta que la operación se haya completado.

Conclusión: Son un tipo de semáforos utilizados cuando tenemos varias instancias


de un mismo recurso. Este tipo de semáforos se inicializa al número de instancias
que tengamos.

3. Monitores
Un monitor es una estructura formada por una cabecera que los identifica, un conjunto
de variables globales a todos los procedimientos del monitor, un conjunto de
procedimientos y un bloque de inicialización, el cual se ejecuta una única vez, cuando
se crea el monitor.

1{ nombre
2{ variables globales accesibles desde todos los procedimientos
3{ procedimiento A
4{ procedimiento B
5{
6
7{ inicialización (solo se ejecuta una vez)

El recurso que queremos compartir (S.C.) se declara como monitor y en él se incluyen


todas las operaciones que afecten a dicho recurso. Los procesos que usan el monitor
se sitúan de forma independiente y cuando deseen usar el recurso, llamarán al
procedimiento del monitor que implemente la operación que desea ejecutar. Para
resolver la sincronización se utilizan dos instrucciones, wait (bloquea siempre) y
signal, y actúan sobre variables condición que son colas y además no tienen valor.
cwait (c): suspende la ejecución del proceso que llama bajo la condición c. El monitor
está ahora disponible para ser usado por otros procesos.
csignal(c): reanuda la ejecución de algún proceso suspendido después de un cwait
bajo la misma condición. Si hay varios procesos, se elige uno de ellos; si no hay
ninguno, no hace nada.
Las colas son un tipo de variables que son el lugar donde almacenaremos los
procesos que hayan quedado suspendidos bajo un .wait. y estén a la espera de ser
"despertados".
En el caso de que dentro de un monitor un proceso se quede bloqueado con un wait
por lo cual se bloquea y no dejaría ejecutarse a otro proceso, el SO despierta a otro
proceso cuya última instrucción haya sido un signal y además vale la condición que
hace que se bloqueen los procesos.
Habrá algunos casos en los que nos apoyemos en una variable booleana para
garantizar la exclusión mutua sobre una variable con una sola instancia. También
habrá casos en los que utilicemos un contador.
Ventajas:
• Mantenimiento más simple
• Menos errores de programación
• La interfaz del monitor es un conjunto de funciones que representan las diferentes
operaciones que pueden hacerse con el recurso.
• La implementación del monitor garantiza la exclusión mutua
• Mediante semáforos o algún otro mecanismo.
• Implícitamente en los lenguajes concurrentes.
Se pueden implementar en memoria u otros recursos compartidos
NOTA: Dentro de los monitores se implementan los semáforos.

4. Algoritmo de Decker
Solución que garantiza la exclusión mutua al gestionar elegantemente este proceso.
Utiliza, además de las banderas de intención de entrar, una variable turno (proceso
favorecido) que resuelve en caso de conflicto.
Da la posibilidad de que el otro proceso entre en su sección crítica una segunda vez si
lo hace antes que el proceso que acaba de dejar el bucle de espera, asigne el valor
cierto a su intención de entrar. Pero cuando de nuevo tiene el procesador, realiza la
asignación y es su turno, así que se ejecuta.

En consecuencia, no produce aplazamiento indefinido.


La solución se desarrolla por etapas. Este método ilustra la mayoría de los errores
habituales que se producen en la construcción de programas concurrentes.
1- Primer intento
Cualquier intento de exclusión mutua debe depender de algunos mecanismos básicos
de exclusión en el hardware. El más habitual es que sólo se puede acceder a una
posición de memoria en cada instante, teniendo en cuenta esto se reserva una
posición de memoria global llamada turno. Un proceso que desea ejecutar su sección
crítica primero evalúa el contenido de turno. Si el valor de turno es igual al número del
proceso, el proceso puede continuar con su sección crítica. En otro caso el proceso
debe esperar. El proceso en espera, lee repetitivamente el valor de turno hasta que
puede entrar en su sección crítica. Este procedimiento se llama espera activa.
Después de que un proceso accede a su sección crítica y termina con ella, debe
actualizar el valor de turno para el otro proceso.

2- Segundo intento:
Cada proceso debe tener su propia llave de la sección crítica para que, si uno de ellos
falla, pueda seguir accediendo a su sección crítica; para esto se define un vector
booleano señal. Cada proceso puede evaluar el valor de señal del otro, pero no
modificarlo. Cuando un proceso desea entrar en su sección crítica, comprueba la
variable señal del otro hasta que tiene el valor falso (indica que el otro proceso no está
en su sección crítica). Asigna a su propia señal el valor cierto y entra en su sección
crítica. Cuando deja su sección crítica asigna falso a su señal.
Si uno de los procesos falla fuera de la sección crítica, incluso el código para dar valor
a las variables señal, el otro proceso no se queda bloqueado. El otro proceso puede
entrar en su sección crítica tantas veces como quiera, porque la variable señal del otro
proceso está siempre en falso. Pero si un proceso falla en su sección crítica o
después de haber asignado cierto a su señal, el otro proceso estará bloqueado
permanentemente.

3- Tercer intento
El segundo intento falla porque un proceso puede cambiar su estado después de que
el otro proceso lo ha comprobado, pero antes de que pueda entrar en su sección
crítica.
Si un proceso falla dentro de su sección crítica, incluso el código que da valor a la
variable señal que controla el acceso a la sección crítica, el otro proceso se bloquea y
si un proceso falla fuera de su sección crítica, el otro proceso no se bloquea.
Si ambos procesos ponen sus variables señal a cierto antes de que ambos hayan
ejecutado una sentencia, cada uno pensará que el otro ha entrado en su sección
crítica, generando así un interbloqueo.
4- Cuarto intento
En el tercer intento, un proceso fijaba su estado sin conocer el estado del otro. Se
puede arreglar esto haciendo que los procesos activen su señal para indicar que
desean entrar en la sección crítica, pero deben estar listos para desactivar la variable
señal y ceder la preferencia al otro proceso.
Existe una situación llamada bloqueo vital, esto no es un interbloqueo, porque
cualquier cambio en la velocidad relativa de los procesos rompería este ciclo y
permitiría a uno entrar en la sección crítica. Recordando que el interbloqueo se
produce cuando un conjunto de procesos desea entrar en sus secciones críticas, pero
ninguno lo consigue. Con el bloqueo vital hay posibles secuencias de ejecución con
éxito.

Una solución correcta


Hay que observar el estado de ambos procesos, que está dado por la variable señal,
pero es necesario imponer orden en la actividad de los procesos para evitar el
problema de "cortesía mutua". La variable turno del primer intento puede usarse en
esta labor, indicando que proceso tiene prioridad para exigir la entrada a su sección
crítica.

5. Algoritmo de Peterson

5.1 Fundamento del Algoritmo de Peterson


Cuando dos o más procesos secuenciales en cooperación ejecutan todos ellos
asíncronamente y comparten datos comunes se produce el problema de la sección
crítica.
Un proceso productor genera información que es utilizada por un proceso
consumidor. Para que los procesos productores y consumidores ejecuten
concurrentemente, tenemos que creer un conjunto de buffers que puedan ser
alimentados por el productor y vaciados por el consumidor.

El consumidor tiene que esperar si todos los buffers se encuentran vacíos, y el


productor tiene que esperar si todos los buffers están llenos.

Una solución simple al problema de la sección crítica nos la proporciona Peterson.


Esta solución es básicamente una combinación del Algoritmo que asocia cada
proceso con su variable de cerradura y de una pequeña modificación del Algoritmo
de Alternancia Estricta.
5.2 Solución a la Exclusión Mutua: Algoritmo de Peterson
Simplifica el algoritmo de Decker.

El protocolo de entrada es más elegante con las mismas garantías de exclusión


mutua, imposibilidad de bloqueo mutuo y de aplazamiento indefinido.

El algoritmo de Peterson es un algoritmo de programación concurrente para


exclusión mutua, que permite a dos o más procesos o hilos de ejecución compartir
un recurso sin conflictos, utilizando sólo memoria compartida para la
comunicación.

El algoritmo de Decker resuelve el problema de la exclusión mutua, pero mediante


un programa complejo, difícil de seguir y cuya corrección es difícil de demostrar.
Peterson ha desarrollado una solución simple y elegante. Como antes, la variable
global señal indica la posición de cada proceso con respecto a la exclusión mutua
y la variable global turno resuelve los conflictos de simultaneidad.

Considérese el proceso P0. Una vez que ha puesto señal[0] a cierto, P1 no puede
entrar en su sección crítica. Si P1 esta aun en su sección crítica, entonces señal[1]
= cierto y P0 está bloqueado en su bucle while. Esto significa que señal[1] es cierto
y turno = 1. P0 puede entrar en su sección crítica cuando señal[1] se ponga a falso
o cuando turno se ponga a 0. Considérense ahora los siguientes casos
exhaustivos:

1. P1 no está interesado en entrar en su sección crítica. Este caso es imposible


porque implica que señal[1] = falso.
2. P1 está esperando entrar en su sección crítica. Este caso es también imposible
porque si turno = 1, P1 podría entrar en su sección crítica.
3. P1 entra en su sección crítica varias veces y monopoliza el acceso a ella. Esto no
puede pasar porque P1 está obligado a dar a P0 una oportunidad poniendo turno a
0 antes de cada intento de entrar en su sección crítica.
Así pues, se tiene una solución posible al problema de la exclusión mutua para
dos procesos. Es más, el algoritmo de Peterson se puede generalizar fácilmente al
caso de n procesos.
6. Interbloqueo

A cada proceso se le asignan varios recursos para su ejecución. En sistemas de


multiprogramación, uno de los principales objetivos del sistema operativo es el
compartimiento de los recursos. Cuando se comparten los recursos entre una
población de usuarios, cada uno de los cuales mantiene un control exclusivo sobre
ciertos recursos asignados a él, es posible que otros usuarios no terminen sus
procesos (bloqueo entre usuarios).
El bloqueo mutuo puede aparecer de muchas formas:
- Si a un proceso se le asigna la tarea de esperar a que ocurra un evento y el
sistema no incluye providencias para señalar la ocurrencia de dicho evento, habrá
un bloqueo mutuo con un solo proceso. Es muy difícil detectar bloqueos mutuos
de esta naturaleza.
- La mayor parte de los bloqueos mutuos en sistemas reales implican una
competencia entre varios procesos por varios recursos.
Bloqueo mutuo = Deadlock = Abrazo mortal
El bloqueo mutuo o abrazo mortal (deadlock) es el problema más serio que se
puede presentar en un ambiente de multiprogramación. Es la actividad en que
dos o más procesos esperan un recurso (CPU, memoria, entrada/salida) que
nunca les va a ser otorgado.

Recurso 1

Proceso 1 Proceso 2

Recurso 2

Como se ve, aquí el sistema está bloqueado: Proceso 1 tiene a Recurso 1 y necesita a
Recurso 2 para continuar. Y Proceso 2 tiene asignado a Recurso 2, y necesita a Recurso
1 para continuar. Cada proceso espera que el otro libere un recurso que no liberará hasta
que el otro libere su recurso, lo cual no sucederá si el primero no libera su recurso. Aquí
se presenta una espera circular.
Proceso A

CPU
Proceso C
Proceso B

Otro ejemplo, dos procesos adueñados de CPU. Proceso A se ejecuta y llama a Proceso
B, Proceso B se ejecuta y llama a Proceso A,..., si llega otro proceso, no lo van a dejar
entrar a CPU a ejecutarse.

Conclusión

El acceso concurrente a los datos compartidos provoca inconsistencias, salvo que dispongamos de
un mecanismo para asegurar la ejecución ordenada de los procesos cooperantes. esto es, que sólo
permita los intercalados correctos.

También podría gustarte