Sie sind auf Seite 1von 48

EJERCICIOS

REPASO DE CONCEPTOS

3.1 La condición que debe cumplir cualquier solución válida al problema de la


sección crítica y que establece que solo un proceso puede estar ejecutándose en su
sección crítica se denomina________________________________

3.2 La condición que debe cumplir cualquier solución válida al problema de la


sección crítica y que establece que solo los procesos que quieren entrar en sus
secciones críticas son los que intervienen en la elección de cuál entra, se
denomina_________________________

3.3 La condición que debe cumplir cualquier solución válida al problema de la


sección crítica y que establece que la elección de qué proceso entra a ejecutarse en
su sección crítica se debe realizar en un tiempo finito, se
denomina_______________________

3.4 La condición que debe cumplir cualquier solución válida al problema de la


sección crítica y que establece que, una vez que un proceso solicita entrar en su
sección crítica, a éste no se le postergará indefinidamente su entrada, se denomina
____________________

3.5 La instrucción hardware para sincronización que consiste en devolver el valor


del operando binario que se le pasa y asignarle a este operando el valor verdadero, se
denomina_________________

3.6 La instrucción hardware para sincronización que consiste en intercambiar los


valores de los dos operandos que utiliza, se denomina__________________

3.7 La operación de un semáforo que decrementa el valor de éste y que además


puede provocar el bloqueo del proceso que la invoca, se
denomina_________________
3.8 La operación de un semáforo que provoca el incremento del valor asociado al
semáforo se denomina____________________________

3.9 Cuando el valor asociado a un semáforo solo puede tomar dos valores (verdadero
o falso), entonces decimos que se trata de un semáforo__________________

3.10 Todo sistema ________________es también un sistema______________, dado


que ambos implican existencia simultanea de varios procesos en ejecución. La
afirmación contraria no siempre es cierta.

3.11 La variante del problema de tos lectores y escritores que exige que no se
mantenga esperando ningún lector a menos que un escritor ya haya obtenido
permiso para usar el objeto compartido se denomina____________________

3.12 La variante del problema de los lectores y escritores que exige que ningún lector
nuevo pueda comenzar a leer si un escritor está esperando para acceder al objeto se
denomina_____________

3.13 La construcción lingüística de alto nivel que consiste en un tipo abstracto de


datos y que además por definición garantiza la exclusión mutua en todos sus
métodos o funciones miembro se denomina

3.14 La herramienta de sincronización posee entre sus operaciones una que provoca
el bloqueo incondicional del proceso que la invoca.

3.15 La construcción lingüística de alto nivel que garantiza exclusión mutua por
definición y -que permite además establecer una condición de entrada a la sección
crítica que es gestionada por la propia herramienta se denomina________________

3.16 Cuando una operación signal sobre una variable condición despierta a un
proceso bloqueado por haber realizado una operación wait sobre la variable
condición y a su vez bloquea al proceso que invoca dicha operación signal, entonces
estamos ante una variable condición que funciona según el
estilo___________________________
3.17 Cuando una operación signal sobre una variable condición hace que compitan
juntos tanto un proceso despertado por dicha operación (bloqueado por haber
ejecutado previamente una operación wait) como los procesos que quieren entrar en
el monitor, entonces estamos ante una variable condición que funciona según el
estilo

TESTS

3.18 Las variables de tipo condición aparecen en:

a) los semáforos

b) las regiones críticas en general

c) las regiones críticas condicionales

d) los monitores

3.19 Las regiones críticas pueden resolver más problemas de sincronización que los
semáforos

a) verdadero

b) falso

3.20 Un semáforo tiene actualmente el valor 2. Si se ejecuta una operación wait o P


sobre él, ¿qué sucederá?

a) El proceso que ejecuta la operación se bloquea hasta que otro ejecute una
operación signal o

b) Tras hacer la operación, el proceso continuará adelante sin bloquearse

c) El proceso continuará adelante sin bloquearse, y si previamente existían procesos


bloqueados a causa del semáforo, se desbloqueará uno de ellos
d) Un semáforo jamás podrá tener el valor 2, si su valor inicial era O (cero) y se ha
operado correctamente con él

3.21 Los monitores

a) garantizan la espera limitada, pero no la ejecución en exclusión mutua.

b) eliminan la necesidad de utilizar variables de tipo condición

c) son tipos abstractos de datos.

d) todas las anteriores son ciertas

3.22 para resolver el problema de la exclusión mutua, puede emplearse una variable
global turno con el identificador del proceso que tiene derecho a entrar en la sección
crítica. Cada vez que un proceso sale de su SC, cambia el valor de turno al
identificador de otro proceso. Esta solución

a) es correcta

b) no cumple la propiedad de exclusión mutua

c) no cumple la propiedad de progreso

d) no cumple la propiedad de independencia de la arquitectura

3.23 El problema de la sección crítica queda resuelto automáticamente con

a) regiones críticas simples (sin condiciones)

b) regiones críticas condicionales

c) monitores

d) todas son ciertas

3.24 Los semáforos

a) eliminan el problema del interbloqueo.


b) son más potentes que las regiones críticas condicionales

c) tienen dos operaciones públicas (wait y signal)

d) todas las anteriores son ciertas

3.25 El problema de la sección crítica aparece porque

a) existen sistemas de memoria compartida aparte de los de paso de mensajes.

b) la espera activa es insuficiente para resolver la exclusión mutua de procesos


concurrentes. c) la ejecución de porciones de código del sistema operativo
accediendo a tablas protegidas ha de efectuarse en exclusión mutua.

d) varios procesos concurrentes pueden acceder a un mismo conjunto de datos

3.26 El que ciertas instrucciones se llamen "atómicas" significa que

a) No se pueden ejecutar concurrentemente.

b) se tienen que ejecutar dentro de un monitor atómico.

c) se han de ejecutar indivisiblemente

d) no se pueden ejecutar con espera activa

3.27 Se ejecutan consecutivamente dos operaciones P o wait sobre un


semáforo. ¿Es esto posible?

a) Sí

b) Sí, siempre que hayan sido procesos diferentes

c) No

d) No, si las ha realizado un solo proceso

3.28 Los monitores proporcionan exclusión mutua porque


a) Solo un proceso puede estar activo cada vez para ejecutar un procedimiento del
monitor b) Para ello se utilizan variables de condición

c) No proporcionan exclusión mutua

d) Se diseñan mediante procedimientos encapsulados dentro de un módulo

3.29 Una solución correcta al problema de la sección crítica

a) debe garantizar la exclusión mutua

b) debe garantizar que un proceso no interesado en entrar en sección crítica no


impida a otros procesos interesados entrar en ella

c) a) y b) son ciertas

d) a) es cierta y b) lo sería solo cuando se desea obtener una mayor velocidad en la


gestión de la entrada en sección crítica.

CUESTIONES Y EJERCICIOS

3.30 ¿En qué se parece y en qué se diferencia un monitor de un tipo abstracto de


datos?

3.31 A continuación se muestra un algoritmo que trata de resolver el problema de la


sección crítica para dos procesos. Demuestre si es correcto o no (es decir, si satisface
las condiciones que debe cumplir toda solución válida para el problema de la sección
crítica).

bool flag[2]={false, false};



while (true) {
Flag[i] = true;
,While (Flag[j] {
Flag[i) = false;
While (Flag[j]) NULL;
Flag[i] = true;
}
Seccion critica
Flag[i] = false;
Seccion no critica
}
Dónde:

a) flag es una variable compartida por los dos procesos.

b) i y j son constantes locales que sirven para distinguir un proceso de otro:

 Para uno de los procesos: i = 0, j = 1


 Para el otro proceso: i = 1, j = 0

3.32 Durante la ejecución de la sección crítica de un proceso de usuario, ¿puede


suspenderse su ejecución para dar paso a algún otro proceso de usuario? Justifique
su respuesta.

3.33 A continuación se muestra un algoritmo que trata de resolver el problema de la


sección crítica para N procesos. Demuestre si es correcto o no (es decir, si satisface
las condiciones que debe cumplir toda solución válida para el problema de la sección
crítica).

//Variables globales
const int N=...
bool eleccion[N];
int numero[N];
Codigo del Proceso Pk {
int j;
while (true) {
//Inicio de la sección de entrada
eleccion[k]=true;
numero[k]=min(numero[0],numero[1]..., numero[n-1])+1;
eleccion[k]=false;
for(j=0;j<N;j++) {
while (eleccion[j]) no-operar;
while (numero[j]!=0 && ((numero([j],j)<(numero[k],k)) no-operar;
}
//Final de la seccion de entrada
Seccion critica
//Inicio de la seccion de salida
numero[k] := 0;
//Final de la seccion de salida
Seccion restante
}
Siendo:

N: número de procesos que intervienen en el problema de sección crítica

k: indica el proceso que quiere entrar en la sección crítica

mín (v0, vl , , va): función que devuelve el valor mínimo (a, b) < (c, d): devuelve true
si se cumple a < c o ((a = c) y (b < d)), en caso contrario devuelve false;

3.34 ¿Por qué las soluciones al problema de la sección crítica para más de dos
procesos son bastante más complicadas que las soluciones para solo dos procesos
concurrentes?

3.35 Los sistemas operativos actuales disponen de llamadas al sistema para bloquear
el acceso a un archivo. Si un proceso bloquea un archivo, por ejemplo, lock(fichero),
cualquier otro proceso que pretenda acceder al archivo queda bloqueado; este
bloqueo ocurre con cualquier llamada al sistema que implique un acceso al archivo
(incluida la lock). El bloqueo se mantiene hasta que el proceso que retiene el archivo
invoca una operación de desbloqueo (por ejemplo, unlock(fichero)).
a) Ilustre con un ejemplo real la conveniencia de estos servicios de bloqueo y
desbloqueo.

b) ¿Estos servicios tienen utilidad en un sistema no multiprogramado?

c) ¿Estas operaciones se podrían implementar satisfactoriamente como rutinas de


biblioteca, empleando semáforos u otros recursos clásicos de sincronización? Dicho
de otro modo, ¿es necesario que este servicio de bloqueo de ficheros, tal y como se
ha descrito, esté resuelto en el núcleo?

3.36 ¿Qué es la espera activa dentro de la sincronización de procesos? ¿Por qué es un


problema? ¿Cómo se puede resolver?

3.37 ¿Puede el uso de semáforos dar lugar a un problema de inanición?

3.38 ¿Por qué son necesarias las variables de tipo condición en los monitores?

3.39 ¿Por qué se dice que el problema de la sección crítica es un problema de


sincronización entre procesos?

3.40 Demuestre que si las operaciones signal y wait de un semáforo no se ejecutan


atómicamente, el semáforo no funciona correctamente.

3.41 Enumere las ventajas e inconvenientes que tienen los monitores sobre las
regiones críticas.

3.42 En un sistema que careciera de herramientas de sincronización, y suponiendo


que los programadores fueran absolutamente infalibles y bienintencionados, ¿se
podría solucionar satisfactoriamente el problema de la exclusión mutua?

PROBLEMAS

3.43 Implemente un objeto que se comporte como un semáforo, a partir de cerrojos y


variables condición como herramientas de sincronización. Es decir, el objeto debe
ofrecer las mismas operaciones que un semáforo y éstas deben estar implementadas
por medio de cerrojos y variables condición.

3.44 En sistemas multitarea queremos administrar el acceso a un recurso de uso


exclusivo. Los procesos adquieren y liberan el recurso mediante las funciones enteras
int Pido_Recur - s o ( int pid) e int Libero_Recurso ( int pid) ,
respectivamente. El parámetro pid sirve de identificador de proceso. Se trata de
implementar estas dos subrutinas utilizando cerrojos y variables condición como
herramientas de sincronización. Su implementación deberá cumplir estas
especificaciones:

 Si un proceso pide el recurso y ya está asignado, el procese queda bloqueado


hasta que el sistema le entregue el recurso.
 Si el proceso que pide el recurso ya lo tiene asignado, la rutina Pido_Recurso (
) retornará de inmediato devolviendo un código de error (-1).
 La rutina Libero_Recurso ( ) solo la puede ejecutar correctamente el proceso
que posee el recurso. Si es invocada por un proceso que no posee el recurso, o
mientras el recurso está libre, la función deberá retornar inmediatamente
devolviendo un código de error (-1).
 Cuando el recurso se libere, se deberá asignar al proceso que lo solicitó hace
más tiempo. Si no hay nadie esperando, el recurso queda libre.
 Si las subrutinas retornan correctamente, devuelven el valor cero.

3.45 Construya un monitor que gestione una comunicación sencilla entre procesos
mediante dos primitivas de envío y recepción de mensajes, cumpliendo estas
especificaciones:

 Para las transacciones existe un tipo de datos llamado mensaje que se supone
ya definido. Los procesos participantes en la comunicación poseerán
identificadores enteros positivos. Existe un máximo de procesos dialogantes,
llamémoslo num_proc (que es constante).
 El monitor contendrá un búfer de M ranuras (M será alguna constante) de
tipo mensaje.
 Como repositorio de transacciones pendientes. Podrán definirse estructuras y
variables adicionales, pero ninguna más de tipo mensaje.
 El monitor ofrecerá dos procedimientos públicos con esta sintaxis:
enviar ( var m:mensaje, destino : intege, quien_soy: integer ) ;
recibir ( var m: mensaje, quien_soy : integer ) ;
 El parámetro destino del procedimiento enviar indica a qué proceso se desea
emitir el mensajero.
 El parámetro quien_soy de recibir expresa qué proceso está demandando
mensajes.
 El procedimiento enviar deposita el mensaje en en el búfer y lo deja
disponible para su consumo; si el búfer está lleno el proceso llamador se
bloquea hasta que haya hueco.
 Si se produce el bloqueo no se impide a otros procesos utilizar el monitor
(que quizás vacíen el búfer).
 El procedimiento recibir bloqueará al proceso llamador hasta que exista
algún mensaje destinado a tal proceso. Este bloqueo no impedirá a otros
procesos utilizar el monitor si están capacitados para ello. Si existe al menos
un mensaje destinado al invocante de recibir, en el parámetro m se copia el
mensaje llegado en primer lugar de todos los posibles, y se elimina del búfer
del monitor (un mensaje solo ge recibe una vez).
 Inicialmente el monitor no contiene mensajes.

No es necesario definir prioridades entre emisores y receptores, pero si se atreve y


tiene tiempo, déle más prioridad a los receptores.

Pregunta adicional 1: ¿Se le ocurre algún motivo para ello?

Pregunta adicional 2: ¿Puede producirse interbloqueo en este sistema?, ¿e


inanición?
3.46 Describa una solución al siguiente problema de sincronización utilizando
semáforos: un proceso C debe empezar a ejecutarse cuando alguno de dos procesos
A o B termine.

3.47 Desarrolle una solución al problema de los lectores y escritores con prioridad
para los procesos escritores empleando:

a) Semáforos

b) RCC

c) Monitores

3.48 Implemente un semáforo binario utilizando monitores.

3.49 En una tienda de pájaros están teniendo problemas para tener a todos sus
canarios felices. Los canarios comparten una jaula en la que hay un plato con alpiste
y un columpio para hacer ejercicio. Todos los canarios quieren inicialmente comer
del plato y después, columpiarse. Pero se encuentran con el inconveniente de que
solo tres de ellos pueden comer del plato al mismo tiempo y solo uno puede
columpiarse. Defina un proceso que ejecuten los canarios concurrente-mente de
forma que sincronicen sus actividades empleando:

a) Semáforos

b) RCC

e) Monitores

3.50 Diseñe una solución al primer problema de los lectores y escritores (prioridad
para los lectores), añadiendo el requisito de que no puede haber más de 20 lectores
simultáneos. La solución consistirá en el código que ha de ejecutar un proceso lector,
y el que ha de ejecutar un proceso escritor. Desarrolle una solución empleando:

a) Semáforos
b) RCC

e) Monitores

3.51 Desarrolle una solución al problema de los filósofos comensales, libre de


interbloqueos, utilizando como herramienta de sincronización solo la función
hardware Test_and_Set.

3.52 En un sistema existen un proceso denominado servidor y un conjunto de


procesos clientes de él. Los clientes, en un momento dado de su ejecución, solicitan
al proceso servidor un determinado servicio.

El comportamiento de los clientes y del servidor debe cumplir las siguientes reglas:

1. Si al servidor no le requieren su servicio entonces debe estar bloqueado.

2. El servidor solo puede satisfacer a un solo cliente en cada momento.

3. Si un cliente pide servicio y el servidor está ocupado, entonces el cliente debe


esperar.

4. Como máximo solo puede haber 10 clientes esperando por ser servidos. (Si un
cliente intenta pedir servicio habiendo ya otros diez clientes en cola, no se realiza la
petición.)

Desarrolle una solución empleando:

a) Semáforos

b) RCC

e) Monitores

3.53 Para cada una de las siguientes descripciones de funcionamiento de las variables
tipo condición, realice una implementación del tipo monitor utilizando semáforos:
a) Cuando un proceso realiza un signal, entonces sale inmediatamente del monitor;
si hay procesos detenidos por haber realizado anteriormente un wait, se producirá la
reanudación de uno de ellos. h) Cuando un proceso realiza un wait, entonces se
bloquea hasta que otro proceso, después de haber realizado un signal, sale del
monitor o bien se bloquea al realizar un wait.

3.54 En cierto sistema concurrente, cada proceso tiene asignado un peso W (es un
entero positivo). Los procesos acceden a un archivo compartido, pudiendo trabajar
concurrentemente con él, pero con la restricción de que la suma total de los pesos de
los procesos que actualmente están trabajando con el archivo tiene que mantenerse
por debajo de cierto límite W.

Diseñe el método de acceso al fichero, mediante dos operaciones EmpiezaAcceso


(Wi) y TerminaAcceso (Wi), donde 13/4 es el peso entero del proceso, empleando:

a) Semáforos

b) RCC

c) Monitores

3.55 Realice una implementación de las regiones críticas condicionales empleando


semáforos.

SOLUCIONES

Repaso de conceptos

3.1. Exclusión mutua

3.2. Progreso

3.3. Progreso

3.4. Espera limitada c

3.5. Test_and_Set
3.6 Swap

3.7. P

3.8. V

3.9. Binario

3.10. Paralelo, concurrente

3.11. Primer problema de los lectores y escritores

3.12. Segundo problema de los lectores y escritores

TESTS

3.18. d

3.19. b

3.20. b

3.21. c

3.22. c

3.23. d

3.24. c

3.25. d

3.26. c

3.27. a

3.28. a

3.29. c
CUESTIONES

3.30 Todo monitor es un tipo abstracto de datos o sea, entidades que definen datos y
métodos para manipularlos. Difieren en que el monitor garantiza por definición
exclusión mutua en todos sus métodos y funciones, es decir, desde que un proceso
invoque a un método del monitor y se encuentre ejecutando sus instrucciones,
cualquier otro proceso que intente acceder al mismo (bien a través de la misma
función miembro o a través de cualquier otra) quedará bloqueado a la espera de que
el proceso que se encuentra ejecutando uno de los métodos del monitor lo
abandone.

3.31 Para comprobar que el algoritmo es correcto, hay que demostrar que cumple las
tres condiciones de exclusión mutua, progreso y espera limitada.

La condición de exclusión mutua se cumple. Mientras un proceso está en sección


crítica, su flag está a True, con lo cual impide al otro proceso superar el bucle while.
Si ambos procesos pretenden entrar al mismo tiempo, puede verse que al menos uno
de los dos quedará detenido en el bucle while.

La condición de progreso también se cumple, porque si un proceso no desea entrar


en sección crítica, su flag está a False y con ello no impide al otro proceso entrar, si
éste lo desea (no entra en el bucle while).

Pero la condición de espera limitada no se cumple. Podemos verlo si ambos


procesos intentan entrar en la sección crítica a la vez y avanzan al mismo ritmo.
Ambos pondrán su flag a True, con lo cual los dos entrarán en el bucle while. En cada
iteración, los dos procesos colocan temporalmente su flag a false, superan el while
interior, vuelven a poner su flag a True y entran en otra iteración. Esta situación
puede repetirse indefinidamente; no hay garantía formal de que el número de
iteraciones esté acotado. Por tanto no se cumple la condición de espera limitada y
existe riesgo de inanición para ambos procesos.

Por tanto, el algoritmo no es correcto.


3.32 Cierto. La ejecución de la sección crítica impedirá progresar solo a procesos
interesados en ejecutar una sección de código que entre en conflicto con la actual,
pero no afecta al resto de los procesos. Incluso se podría ceder la CPU a un proceso
que no puede progresar, por ejemplo si el mecanismo que se adopta para el bloqueo
es mediante espera activa.

3.33 La solución propuesta es una versión errónea del algoritmo de la panadería de


Leslie Lampert. La elección del número de turno del algoritmo original se hace
dándole al proceso el máximo valor de los turnos de sus compañeros, más uno. Aquí
se ha cambiado el máximo por el mínimo. Esto conduce a un algoritmo totalmente
inútil y absurdo.

Puede comprobarse que cuando el proceso calcula su número [k] a partir del
mínimo de los valores de numero E, se devolverá siempre un uno. Esto ocurre
porque el mínimo encontrado siempre es cero, que es el valor que precisamente tenía
numero [1(] antes de empezar a buscar el mínimo.

Lo anterior significa que los valores de número [k] solo pueden ser:

— cero (el proceso no está interesado en entrar mi sección crítica).

— uno (el proceso quiere entrar en sección crítica). A su vez, eso significa que la
línea

while (numero [j]1.0 && (numero ( [j],j)< (numero [k] ,k) ) no-operar;

realmente es equivalente a:

while ( (numero [j]==1) && (j<k) ) no-operar;

O sea, que un proceso K espera por otro proceso J si y solo si el proceso J quiere
entrar en sección crítica y el identificador de J es menor que el de K. Esto significa
que si el proceso 10 está dentro de la sección crítica y el proceso 5 está interesado en
entrar, este último NO esperará por el proceso 10 y entrará sin más en sección
crítica. Es más, si llega el proceso 3, también entrará en sección crítica, porque no
esperará ni por el 5 ni por el 10. Por tanto, se viola flagrantemente el requisito de
exclusión mutua.

Al no verificarse la exclusión mutua, no tiene sentido examinar las propiedades de


progreso o espera limitada. La solución no es válida.

Esto puede verse con más claridad si reducimos el problema a N = 2 procesos. El


código de los dos procesos quedaría como sigue:

Proceso 0. Proceso 1.

eleccion[0]=true eleccion[1]=true

numero[0]=1 numero[1]=1

eleccion[0]=false eleccion[1]=false

while (eleccion[1]) no-operar; while(eleccion[0])no-


operar;while (numero[0]==1) no-operar;

Seccion Crítica Seccion Critica

numero[0]=0 numero[1]=0

Seccion Restante Seccion Restante

Puede verse que el proceso O no tiene en cuenta al proceso 1 para entrar en sección
crítica (solo se podría bloquear brevemente mientras eleccion [ 1 ] sea cierto, cosa
que solo ocurre fugazmente, mientras el proceso 1 está lijando el valor de numero
[11). En otras palabras, el proceso O entra en la sección crítica cuando quiere, incluso
si el proceso 1 está dentro.

Progreso. Sí la cumple ya que, por un lado, solo los que quieren entrar en la sección
crítica influyen en la elección de quién entra (tendrán sus elementos de número
asociados a va-lores distinto de cero), y por otro lado, la elección siempre se realiza
en un tiempo finito (en caso de existir varios con un mismo valor de número,
entonces entra el que posea un menor identificador de proceso).
Espera limitada. No la cumple ya que existe la posibilidad de que varios procesos
posean un mismo valor de número debido a la fórmula empleada para su obtención
(que no tiene en cuenta el orden de petición). De hecho, los únicos valores de
número son 0 o 1. Si esto ocurriese siempre entraría aquél con un identificador
menor, por tanto, se podría producir un "castigo" a aquellos procesos que posean
identificadores mayores.

3.34 Porque al intervenir más procesos, garantizar el cumplimiento de las


condiciones de progreso y espera limitada es más complejo.

3.35 Solución:

a) Para ilustrar su conveniencia, serviría cualquier ejemplo donde sea necesario el


acceso exclusivo a algún registro del archivo. Por ejemplo, las transferencias
bancarias, donde el saldo de una cuenta se almacena en un campo de un registro
asociado a la cuenta. Otra utilidad: suponga que dos usuarios están accediendo
mediante un programa editor al mismo fichero texto.

b) Estas operaciones carecen de utilidad en un sistema no multiprogramado, ya que


no hay otros procesos concurrentes a los que bloquear.

c) Es técnicamente posible, pero no se podría garantizar el bloqueo del fichero, ya


que el bloqueo de un fichero puede ser ignorado por cualquier proceso que haga
directamente una llamada al sistema (no se puede alterar la implementación de las
llamadas al sistema).

3.36 El problema de la espera activa consiste en asignar la CPU a un proceso que


evalúa continuamente una condición que es falsa y que en caso de no tener más de
un procesador, no cambiará de estado mientras dicho proceso tenga asignada la
CPU, por lo que en este tipo de sistemas será siempre un tiempo perdido que podría
ser aprovechado por otros procesos. Una forma de resolver la espera activa es
bloquear los procesos de forma que solo sean despertados cuando la condición por la
que quedaron bloqueados se vuelva cierta. De este modo estos procesos no ocuparán
tiempo de CPU inútilmente.

3.37 Los semáforos son tan solo una herramienta para la sincronización de procesos
concurrentes. No resuelven por sí solos ningún problema de gestión de recursos
como el interbloqueo o la inanición.

Por ejemplo, pueden usarse semáforos para controlar el acceso a un recurso


compartido, en el que se concede el acceso al proceso con más prioridad. Este tipo
de políticas tienen riesgo de inanición.

3.38 Para que un proceso dentro de un monitor pueda esperar por un evento sin que
acapare el uso del monitor y sin necesidad de recurrir a semáforos u otras
construcciones.

3.39 Porque trata de que solo un proceso dentro de un grupo pueda ejecutar código
de sección crítica; por tanto los restantes procesos han de esperar y el grupo ha de
sincronizarse.

3.40 Por ejemplo, si se entremezcla la ejecución de dos instrucciones wait sobre un


mismo semáforo inicializado a uno, ambos procesos podrían evaluar
simultáneamente que el semáforo tiene valor cero y tomar los dos la decisión de
avanzar sin bloquearse. Ese comportamiento sería incorrecto, ya que solo debería
avanzar uno de los dos procesos.

3.41 Ventajas de los monitores clásicos sobre las regiones críticas condicionales: Los
monitores no permiten construir regiones críticas en cualquier punto del programa,
ya que todos los accesos a los datos están encapsulados como operaciones públicas
del monitor. Esto genera dos ventajas:

 garantiza la integridad del recurso compartido.


 facilita el análisis y el mantenimiento del código.

Además de lo anterior, tenemos que:


 las variables condición permiten una implementación más eficiente que las
regiones críticas condicionales, en lo que se refiere a la gestión de los procesos
en espera condicional.

Los inconvenientes de los monitores respecto a las regiones críticas:

 obligan al programador a escribir expresamente cuándo se deben desbloquear


los procesos en espera por condiciones (mediante operaciones wait). En las
regiones críticas, esto ocurre de forma transparente al programador.
 Se han definido varias semánticas de las variables condición (Mesa, Hoare,
etc.), así que un programa que funciona para ciertas semánticas puede no
funcionar con otras.

3.42 Sí, ya que es posible implementar soluciones software al problema de la sección


crítica Sin embargo este tipo de soluciones tienen dos inconvenientes: por un lado la
complejidad de los algoritmos y por otro lado el problema de la espera activa.

Problemas

3.43 En esencia, el semáforo es una variable entera a la que se accede de forma


exclusiva mediante un cerrojo. El bloqueo de la operación wait del semáforo se
consigne con una variable condición.

class Semáforo private


{
private
int valor; // el valor inicial lo pone el usuario
Lock cerrojo; // para acceder al valor de forma exclusiva
Condition espera; // para bloquear a los procesos que
// intentan hacer un wait con el valor a cero
public: void Semaforo(int valor_inicial) { valor=valor_inicial;
void WAIT()
{
cerrojo.acquire(); // acceso exclusivo a “valor”
// me bloqueo si el valor es cero
if ( valor==0) {
espera.Wait();
}
valor--;
cerrojo.Release();
void SIGNAL()
cerrojo.acquire(); // acceso exclusivo a "valor"
valor++; espera.Signal(); // aviso a un proceso bloqueado (si lo hay)
cerrojo.Release();
}
};
3.44 En esta propuesta se utiliza el estilo finare para las variables de tipo condición.
Recuérdese que en este estilo cuando un proceso realiza una operación signal sobre
una variable de tipo condición cede el cerrojo al proceso que había hecho una
operación wait y se bloquea. El proceso que había realizado la operación wait entra
en ejecución inmediatamente. El proceso que hizo la operación signal tiene que
esperar a tomar de nuevo el control del cerrojo para seguir ejecutándose.

Un ejercicio que se plantea al lector es comprobar si la solución aportada serviría si


se utilizaran variables de tipo condición según el estilo de Mesa y de no ser válida
aportar una solución.

class Planificador {
private:
int proceso:
bool ocupado: //Indica si el recurso esta asignado o no.
Lock *llave;
Condition *turno; // vinculada al cerrojo "Llave"
int Nespera; //Indica cuantos procesos esperan por el recurso public:
void planificador() {
llave = new(Lock);
turno = new(condition):
ocupado = false;
proceso = -1;
Nespera = O;
);
void planificador() {
assert(ocupado == false);
assert(Nespera == O)
delete llave;
delete turno; };
int pido_recurso( int pid ) {
int retorno;
llave.acquire();
if ((ocupado== true) && (proceso==pid) ) {
retorno = -1
else {
if (ocupado== true) {
nespera = Nespera + 1;
turno.wait(): Nespera = Nespera - 1;
ocupado = true;
proceso = pid;
retorno = O;
llave.
Release();
return(retorn0):
} ;
int libero_recurso( int pid ) {
int retorno;
Llave.acquire () ;
if ((Ocupado = falso) H (Proceso = pid) ) {
retorno = -1;
else {
Ocupado = false; if ( Nespera > O )
Turno.signal()
llave.release();
Return (retorno);
};
}:
3.45 Solución:

Monitor Buzon
{
mensaje buffer[M];
int destinatario[M], mensajes_pendientes[num_proc];
int inserto[num_proc], extraigo[num_proc], nhuecos;
ínt nhuecos;
Condition hay_hueco, hay_mensaje[num_proc];
void Buzon() {
for ( i = 0 ; i < num_proc; i++) {
extraigo[i] = O;
inserto[i] = O;
mensajes_pendientes[destino] = O;
destino[i] = -1;
}
nhuecos = M;
};
void enviar (mensaje m, int destino, int quien_soy)
{
integer k;
if ( nhuecos == O ) {
hay_hueco.wait;
k = inserto[quien_soy]%M;
nhuecos--;
buffer [k] =m;
destinatario[k] = destino;
inserto{quien_soy}= (k+l)%M;
mensajes_pendientes[destino)++
,hay_mensajes[destino].signal;
};
Void recibir (mensajes m, int quien_soy)
{
Integer k;
If (hay_mensaje[quien_soy].wait;
}
K=extraigo(quien_soy);
do{
if destino[k] == quien_soy )
m = buffer[k];
destino[k] = -1;
extraigo[quien_soy] = (k+l)%M;
nhuecos++;
mensajes_pendientes[destino]--;
return;
else {
k = (k+l) %M;
}
while ( k != extraigo[quien_soy] );
return; );
};
};
El motivo de que los receptores deben tener mayor prioridad se debe a que de esta
forma se intenta evitar la saturación del búfer de mensajes. Se puede producir
interbloqueo entre dos procesos que esperan mutuamente por mensajes enviados
por el otro proceso.

No se produce inanición debido a que los procesos entran por orden de llegada y se
salen del estado de bloqueo, variables condición, también por orden.

3.46 Solución:

Semaphore sem(0) ;
Proceso A:
... instrucciones de A...
sem.V();
Proceso B:
... instrucciones de B...
sem.V();
Proceso C:
sem-P();
... instrucciones de C...
Comentario: cuando el primero de los procesos A o B finalice, hace una operación V
sobre el semáforo, con lo cual permite a C ejecutarse. La segunda operación V no
provoca ningún efecto en C, incluso aunque suceda antes de que C ejecute la
operación P.

3.47 Solución:

a) Semáforos
Variables globales
Semaphore mutex (1) , lector ( O ) , escritor (0) :
int n1=0, nle=0, nee=0;
bool escribiendo=false;
Codigo del proceso Lector {

mutex.P();
if (escribiendo I I nee>0) {
nle++;
mutex.V();
lector.P();
nle++;
if (nle>0)
lector .v( ) ;
else mutex.V ( ) ;
LEER DEL RECURSO
mutex.P();
nl--;
if (n1==0 && nee>0)
escritor.V();
else mutex.V();

}
Codigo del proceso Escritor {

mutex.P();
if (nl>0 II escribiendo) {
nee++;
mutex.V();
escritor-P();
nee--;
);
escribiendo=true;
mutex.V();
ESCRIBIR EN EL RECURSO
mutex.P();
ne--;
if (nee>0)
escritor.V();
else if (nle>0)
lector...V();
else mutex_V();

}
b)RCC
Variables globales
Shared lect_esc {
int n1=0, nee=0;
bool escribiendo=false;
);
Codigo del proceso Lector {

region lect_esc when (!escribiendo && nee==0) {
n1++;
}
LEER DEL RECURSO
region lect_esc {
nl--;
}

}
Codigo del proceso Escritor {

region lect_esc
nee++ region
lect_esc when (n1==0 && !escribiendo) {
escribiendo=true;
nee--;
ESCRIBIR EN EL RECURSO
region lect_esc { escribiendo=false;
}

}
c) Monitores

Variables globales
Monitor Lectores_Escritores {
int nl, nle, nee;
bool escribiendo;
Condition lector, escritor;
public void Empezar_Lectura() {
if (escribiendo or nee>0) {
nle++ ;
lector _wait O ;
nle--;
nl++; lector .signal();
public void Terminar_Lectura() {
nl--;
if (n1==0)
escritor .signal() ;
}
public void Empezar_ Escritura() {
if (nl! =O 1 1 escribiendo) { nee++ ;
escritor.wait();
nee--;
escribiendo=true;;
}
public void Terminar_Escritura()
escribiendo= false ;
if (nee>0) escritor. signal () ;
else lector.signal();
}
public Lectores_Escritores() {
nl=n1e=nee=0;
escribiendo=false;
; Monitor Lectores_Escritores Lect_Esc;
Codigo del proceso Lector {

Lect_Esc.Empezar_Lectura();
LEER DEL RECURSO
Lect_Esc.Terminar_Lectura();
Codigo del proceso Escritor

{ Lect_Esc.Empezar_Escritura();
ESCRIBIR EN EL RECURSO
Lect_Esc.Terminar_Escritura();

}
}
3.48 Solución:
Notas previas:

 Se supone que una operación V sobre un semáforo que ya tiene el valor 1 deja
inalterado el semáforo.
 La implementación funciona con cualquier semántica de variables condición
(Mesa, Hoa-re, etc.).

monitor BinarySemaphore {
private boolean available;
private Condition queue;
public BinarySemaphore (boolean initialValue)
available = initiaivalue;
public void P () {
while ( ! available ) {
queue.wait ( );
available = false;
}
public void V O {
available = true;
queue.signal();

3.49 Solució n:
a) Semáforos
Semaphore alpiste (3);
Semaphore columpio (1);
void Canario ()
{
alpiste.P();
... comer ...
alpiste.V();
columpio.P();
...columpiarse ... columpio.V();
}
b) RCC
shared Alpiste int comiendo=0;
shared Columpio boolean columpio_libre = true;
void canario ()
region Alpiste when comiendo<3
comiendo++;
…comer…
region Alpiste comiendo--;
region Columpio when columpio_libre
columbio_libre = false;
…columpiarse…
region columpio columpio_libre = true;

c) Monitores
monitor Comedor
{
private int comiendo;
prívate Condition cola_comer;
public Comedor(){
comiendo = O;
}
public void Empieza() {
while ( comiendo == 3 ) {
cola_comer.wait();
} comiendo++;
}
public void Termina() {
comiendo--;
cola_comer.signal();
}
}
monitor Columpio
{
private boolean columpio_libre;
private Condition cola_columpio;
public Columpio() {
columpio_libre = true;
}
public void Empieza() {
while ( ! columpio_libre){
cola_columpio.wait();
}
Public void Empieza () {
While columpio_libre = false;
Cola_columpio.wait();
}
public void Termina() {
columpio_libre = true;
cola_columpiarse.signal();
}
void Canario ()
Comedor.Empieza();
... comer ...
Comedor.Termina();
... columpiarse ...
Columpio.termina();
}

3.50 Solución:

a) Semá foros
Class Lectores_Escritores {
prívate:
semaphore esch(1) mutex (1) , lect (20) ;
int cuentalect;
public:
void escritor() {
esch.P();

Se realiza escritura

esch.V();
) ;
void lector(){
lect.P();
mutex.P()
cuentalect++
if ( cuentalect == 1 ) {
esch . P ()
}
mutex.V1();
Se realiza la lectura;
mutex.P();
cuentalect--;
if ( cuentalect == 0 ) {
esch.V()
}
lect.V();
mutex.y()
};
};
b) RCC
shared control (
int contador=0; }
procedure lector()
region control when (contador<20)
contador:=contador+1;
}
... realiza la lectura …
region control {
contador:=contador-1;
}
}
procedure escritor( )
{
region control when (contador==0)
... realiza la escritura ...
}
};

c) Monitores
Monitor lectores_escritores {
prívate:
int cuentalect;
bool llave_escritura;
condition escr, lect;
public:
void lectores_escritores() {
llave_escritura = false;
cuentalect = 0;
};
void finalizo_escritura( )
if (((cuentalect>0) I I (llave_escritura == true)) { escr .wait () ;
llave_escritura = true; 1
};
void Finalizo_Escritura ()
{
llave_escritura = false;
if (cuentalect == O) {
escr .Signal();
}
};
Void solicito_lectura ()
{
cuentalect++;
if ( cuentalect== 20 ) {
lect.Wait();
};
void Finalizo_Lectura()
{
cuentalect--,
if ( cuentalect >= 20 ) {
lect.Signal();
}
else
if cuentalect == O ) {
llave_escritura = false;
escr.Signal () ;
}
}
};
3.51 Solución:
const int NFILOSOFOS = 5;
bool palillos[NFILOSOFOS]=false, false, false, false, false;
Codigo Filosofo Par {

While (true){
// Pensando…
While (test_and_set (palillo [i]== true;
While (test_and_set (palillo [(i+1)%NFILOSOFOS]== true);

// A comer ...
palillo[i]=false;
palillol(i+1)%NFILOSOFOS]=false;
}
}
Código filosofo impar {

While (true){
//pensando…
While (test_and_set (palillo [(i+1)%NFILOSOFOS]== true);
While (test_and_set (palillo [(i)== true);
// A comer ...
palillo[(i+1)%NFILOSOFOS]===false;
palillol[i]%NFILOSOFOS]=false;
}
}

3.52 Asumiremos que existe una clase TipoColaPeticiones que permite manejar una
cola de peticiones: Insertar (para insertar una petició n en la cola), Extraer (para
extraer una petició n de la cola), Numero_Peticiones (nos indica el nú mero de
peticiones en la cola).

a) Semá foros
Variables globales
Semaphore mutex(1), servidor(0) ;
TipoColaPeticiones cola_peticiones;
Codigo del proceso servidor {
TipoPeticion peticion;
for ( ; ; ) {
. . .
servidor .P( ).;
mutex.P ( ) ;
peticion=cola_peticiones . Extraer ()
mutex . V ( ) ;
//Atender servicio solicitado
peticion. semcliente. V ()

}
}
Codigo de los procesos clientes {
/* Asumimos que uno de los campos de TipoPeticion (semcliente) es un
semaforo inicializado a 0 */
TipoPeticion mipeticion;
...
if(cola_peticiones.Numero_Peticiones()<10)
{ { cola_peticiones.Insertar(mipeticion);
servidor.V();
mutex.V(); mipeticion.semcliente.P(); else mutex.V();
b) RCC
Variables globales
ariables globales
Shared servicios {
TipoColaPeticiones cola_peticiones;
};
Shared servicio_atendido {
/* Asumimos que existe una clase TipoColaPeticionesAtendidas que permite
manejar una cola cuyos nodos contienen los identificadores de los
procesos cuyos servicios han sido atendidos por el servidor: Insertar,
Extraer, Buscar (nos indica si existe un nodo con el identificador pasado
por parametro */
TipoColaPeticionesAtendidas cola_peticiones_atendidas;
}
Codigo del proceso servidor {
TipoPetícion peticion;
for (;;)

region servicio
when(cola_peticiones.Numero_Peticiones()>0{ peticion=cola_peticiones.Ext
raer();
};
// Atender servicio solicitado
Región servicio_atendido{
cola_peticiones_atendidas.Insertar(peticion.Idproceso)
} ;
}

}
Codigo de los procesos clientes {
TipoPeticion mipeticion;
bool maxixtosuperado=false;

region servicio {
if (cola_peticiones.Numero_Peticiones()<10)
cola_peticiones.Insertar(mipeticion);
else maximosuperado=true;
if (!maximosuperado)
region servicio_atendido
when(cola_peticiones_atendidas.Buscar(Idproceso)
{ cola_peticiones_atendidas.Extraer(Idproceso);
} ;

}
c) Monitores
Variables globales
Monitor Servidor_Clientes {
private:
Condition servidor, clientes;
TipoColaPeticiones *cola_peticiones;
public:
void solicitar(TipoPeticion peticion) {
if ( cola_peticiones->Numero_Peticiones ) ==10 )
return;
cola_peticiones->Insertar(peticion);
servidor.signal(); clientes.wait(); )
TipoPeticion atender() {
if (cola_peticiones->Numero_Peticiones()==0)
servidor.wait()
return (cola_peticiones->Extraer());
}
void atendido() {
/* Si asumimos que la gestion de procesos bloqueados de las variables
condicion se realiza siguiendo una politica FIFO basta con esta variable
condicion. En caso contrario deberiamos emplear una variable condicion
para cada cliente. */
clientes.signal()
}
void Servidor_Clientes() {
cola_peticiones= new TipoColaPeticiones;
}
};
Monitor Servidor_Clientes servicio;
Codigo del proceso servidor {
TipoPeticion peticion;
for (;;) {
peticion=servicio.atender();
// Atender servicio solicitado servicio.atendido();

}
}
Codigo de los procesos clientes {
TipoPeticion mipeticion;

servicio.solicitar(mipeticion);

}
3.53 Solución:
a) Cuando un proceso realiza un signal, entonces sale inmediatamente del monitor; si
hay procesos detenidos por haber realizado anteriormente un wait, se producirá la
reanudació n de uno de ellos.

Para garantizar la exclusió n mutua del monitor, en los procedimientos pú blicos se


emplea un semá foro inicializado a uno de la siguiente forma (el semá foro
evidentemente será el mismo para todos los procedimientos exportados del monitor):
mutex.P()
//Cuerpo del procedimiento
mutex.V()
A cada variable condició n se le asocia un semá foro x_mutex inicializado a O, en el que
se bloqueará n los procesos que realicen operaciones wait sobre dicha variable
condició n, empleando una variable entera x_numblog para contabilizar los procesos
bloqueados por operaciones wait
Codigo de la operacion x.mait()
x_numblog++;
mutex.V();
x_mutex.P();
x_numbbloq--;
codigo de la operacion x.signal ()
if (x_numbloq>0)
x_mutex.V{);
else mutex.V();
return //salir del procedimiento del monitor
b) Cuando un proceso realiza un wait, entonces se bloquea hasta que otro proceso,
después de haber realizado un signal, sale del monitor o bien se bloquea.

Todo lo indicado en la implementació n anterior sería vá lido retocando la


implementació n del wait y signal de la siguiente forma:
Codigo de la operacion x.wait()
x_numbloq++;
mutex.V();
x_mutex.P();
mutex.P();
Codigo de la operacion x.signal()
if (x_numblog>0)
X_numbloq--;
X_mutex.V();
}
3.54 Solución:

a) Semáforos
const int W = ...;
Semaphore mutex(1);
Semaphore cola(0) ;
int peso = O;
int esperando = O;
/* ALGORITMO A Sin preferencia para los procesos bloqueados respecto a
los recién llegados. No garantiza que un proceso pueda acceder al recurso
en un tiempo finito. También se hacen más operaciones cola.V() de las
estrictamente necesarias. */

void EmpiezaAcceso ( int wi )


mutex.P();

if ( peso+wi >= W )
esperando++;
do{
mutex.V();
cola.P();
mutex.P();
while ( peso+wi >= W );
esperando--;
}
peso = peso+wi;
mutex.V();
}

/* ALGORITMO B
Con preferencia para los procesos ya bloqueados respecto a los recién
llegados.
Se lanza una cantidad de operaciones cola.V() razonablemente pequeña. ./
// las mismas variables, mas esta:
int despertar= 0;
void EmpiezaAcceso ( int wi ){
mutex.P();
if ( peso+wi >= W ){
esperando++;
do{
desbloquea_siguiente();
cola.P();
} while ( peso+wi >= W );
esperando--;
}
peso = peso+wi;
desbloquea_siguiente();
}
void desbloquea_siguiente() {
if ( despertar > 1 ) {
despertar--;
cola.V();
else {
despertar = O
mutex.V();
}
void TerminaAcceso ( int wi
mutex.P();
peso = peso - wi;
if ( esperando >0 ){
despertar= esperando;
cola.V ()
} else {
mutex.V{}
}
}
b) RCC
const int W = ...;
shared Archivo { int peso=0; }
void EmpiezaAcceso ( int wi ) {
region Archivo when peso+wi < W {
peso = peso + wi
}
}
void TerminaAcceso ( int wi ){
region Archivo
peso=peso +wi;
}
}

c) Monitores
monitor Archivo {
const int W = ...;
private int peso;
private Condition cola;
public Archivo () { peso = 0; }

public Empieza ( int wi ) {


while ( peso + wi >= W ) {
cola.wait();
}
peso = peso + wi;
public Termina ( int wi ) {
peso = peso + wi;
cola.broadcast;
}
}
void EmpiezaAcceso ( int wi ) {
Archivo. Empieza (wi) ;
voíd TerminaAcceso ( int wi ) {
Archivo.Termina(wi)
}
3.55 Una primera solució n simple para implementar una regió n crítica condicional
con semá foros se muestra a continuació n, donde se emplea un semá foro asociado a
cada variable condició n inicializado a uno que permite garantizar la exclusió n mutua
tanto en la secció n crítica como en la evaluació n de la condició n:
region r when B
S;
r-mutex.P();
while (!B)
r-nutex.V();
r-mutex.P()
;
S;
r-mutex:V();
El problema que presenta la implementació n anterior es la espera activa en la secció n
de, entrada a la secció n crítica, donde para evaluar la condició n es necesario liberar el
semá foro r —mutex y volverlo a adquirir. Una implementació n má s compleja pero que
no presenta este problema se muestra a continuació n:
region r when B
S;
//Variables asociadas a cada variable condicion
Semaphore r-mutex(1), r-waít(0) ;
int r-count=0, r-temp=0;
//Inicio de seccion de entrada
r.mutex.P();
if (!B) {
//Si la condicion de sincronizacion es falsa
r-count++;
r-mutex.V();
r-wait.P();
while (!B) {
r-temp++;
if (r-temp<r-count) r-wait.V();
else r-mutex.V();
r-wait.P();
r-count--;
//Fin de seccion de entrada
S;
//Inicio de seccion de salida
if (r-count>0) {
r-temp=0;
r-wait.V();
else r-mutex.V()
}
//Fin de seccion de salida

Das könnte Ihnen auch gefallen