2.6 Secciones Criticas
¿Cómo
evitar las condiciones de competencia? La clave para evitar los problemas en ésta
y otras situaciones relacionadas con la memoria compartida, archivos compartidos
y cualquier otra cosa compartida, es determinar una forma de prohibir que más
de algún proceso lea o escriba en los datos compartidos a la vez. En otras
palabras, lo que necesitamos es la exclusión mutua (una forma de garantizar que
si un proceso utiliza una variable o archivos compartidos, los demás procesos
no puedan utilizarlos).
El
problema de evitar las condiciones de competencia también se puede formular de
manera abstracta. Durante cierta parte del tiempo, un proceso está ocupado
realizando cálculos internos y otras labores que no conducen a condiciones de
competencia. Sin embargo, en algunas ocasiones un proceso puede tener acceso a
la memoria compartida de archivos o realizando labores críticas que pueden
llevar a conflictos. Esa parte del programa, en la cual se tiene acceso a la
memoria compartida se llama la Sección o Región Crítica.
Aunque
esta condición evita los conflictos, no es suficiente para que los procesos
paralelos cooperen en forma correcta y usen de modo eficaz los datos
compartidos.
La
exclusión mutua debe ponerse en práctica, sólo cuando los procesos obtienen
acceso a datos compartidos modificables; cuando los procesos realizan
operaciones que no entran en conflictos con otras, deben permitirse que procedan
concurrentemente.
Cuando
un proceso obtiene acceso a datos compartidos modificables, se dice que se
encuentra en una sección crítica. Para evitar alguna clase de problemas se
debe asegurar que cuando un proceso se encuentre en una sección crítica, los
demás procesos no pueden entrar a sus propias secciones críticas.


Si
un proceso se encuentra en su sección crítica, otros procesos pueden seguir
ejecutándose fuera de sus secciones críticas. Cuando un proceso abandona su
región, otro proceso que esperaba entrar en su propia sección podrá hacerlo.
El problema de la programación concurrente está en que se cumpla la exclusión
mutua.
Cuando
se encuentra en una región crítica se está hablando de un estado especial que
se concede a un proceso. El proceso tiene acceso exclusivo a los datos
compartidos y los demás procesos que requieren acceso a esos datos y en ese
momento deben esperar; por esto las secciones críticas deben ejecutarse tan rápido
como sea posible. Un proceso no se debe bloquear dentro de su propia sección crítica
y estas deben codificarse con mucho cuidado.
Si
un proceso de una sección crítica termina, el S.O. al realizar su
mantenimiento de terminaciones, debe liberar la exclusión mutua para que otros
procesos puedan entrar en sus regiones críticas.
Necesitamos
4 condiciones para poder obtener una buena solución:
1. Dos
procesos no deben encontrarse al mismo tiempo dentro de sus secciones críticas
.
2.
No
se deben hacer hipótesis sobre la velocidad o el número de UCP.
3. Ninguno
de los procesos que estén en ejecución fuera
de su sección crítica puede bloquear a otros procesos.
4. Ningún
proceso debe esperar eternamente para entrar a su sección crítica.
Una gran cantidad de programas que utilizan semáforos, los cuales son un mecanismo de sincronización entre procesos necesitan un protocolo específico para poder funcionar, y se da por sentado que el programador los sigue paso a paso cuando codifica los procesos que usan un recurso compartido.
Algunos de las posibles soluciones que se pueden tener mediante la utilización de regiones críticas cuando se presenta algún problema con los semáforos son las siguientes:
o
Los semáforos no están
relacionados sistemáticamente con los recursos compartidos que guardan.
o
Específicamente no hay
declaraciones que pudieran alertar al compilador de que una estructura de datos
específica está compartida y que su acceso necesita ser controlado.
o
Los semáforos aseguran la comunicación entre procesos a través de
variables globales, pero dichas variables son vulnerables a las manipulaciones
ilegales o insensatas por parte de
los procesos legalmente asignados.
Brinch
Hansen propuso un lenguaje llamado Región Crítica que solucionada algunas de
las carencias presentadas por los semáforos.
Una región crítica protege una
estructura de datos compartida haciéndole saber al compilador que puede generar
una estructura de datos compartida que mantenga el acceso mutuamente exclusivo
a los datos correspondientes.
La declaración de este tipo de variable presenta el siguiente formato:
Var
mutex: shared T;
Donde
shared informa al compilador que la variable mutex, definida por el
usuario como de tipo T, es compartida por varios procesos.
Lo principal de esto es que los procesos pueden acceder a una variable que se
encuentre protegida mediante la construcción región como se presenta a
continuación:
Mediante esta instrucción la sección
que sigue después de do es considerada como sección crítica.
Cuando esto sucede el compilador
inserta dos operaciones, alrededor de la sección crítica,
que son ESPERA y SEÑAL.
Estas declaraciones son necesarias
para habilitar al compilador y asegurar que las operaciones de semáforo no
continúen y prohibir el acceso de las variables compartidas a cualquier
sentencia no correspondiente a la región, ya que, como se comentó, es una de
las carencias que presentan los semáforos.
Las regiones críticas restringen el
uso de variables compartidas
mediante el uso de la declaración propuesta por Brinch Hansen.
Sin embargo, no pueden ayudar a
estructurar los dos usos más frecuentes de los semáforos (la exclusión mutua
y la señalización).
En el caso de la exclusión mutua sí
es posible solucionar el problema que presentan los semáforos con la región
critica pero no lo sucede o mismo con la señalización.