Clase 6 y 7 - Campus Virtual

Anuncio
Sistemas operativos
Comunicación y sincronización de procesos
Comunicación y sincronización de
procesos
Contenido
1. Introducción
2. Comunicación por memoria común
3. El problema de la sección crítica
4. Soluciones hardware
5. Soluciones por software
6. Mecanismos de comunicación y sincronización
- Semáforos
- Tuberías
-Mutex y variables condicionales
7. Problemas clásicos de programación concurrente
8. Comunicación por mensajes
Introducción
●
●
●
Un programa concurrente es aquel que contiene uno o
más procesos que trabajan en forma conjunta para
realizar una tarea
Procesos concurrentes entonces:
●
Compiten por recursos (tanto físicos como lógicos)
●
Se comunican entre si
Los procesos concurrentes se pueden ejecutar en los
siguientes modelos de computadora:
●
Multiprogramación: con un solo procesador
●
Multiprocesador: memoria compartida.
●
Multicomputadora → memoria distribuida – mensajes
Introducción
●
●
●
Existe la necesidad de comunicación entre procesos.
Los procesos requieren con frecuencia comunicación
entre ellos.
La comunicación entre procesos puede seguir dos
esquemas básicos:
●
Comunicación por memoria común
●
Comunicación por mensajes
Comunicación por memoria común
●
La comunicación por memoria común se puede dar en
los siguientes casos:
●
●
●
Espacio de direcciones único: es el caso de los hilos de
ejecución
El s.o. crea una zona de memoria accesible a un grupo
de procesos
Problema de la sección crítica
Comunicación por memoria común
●
Ejemplo: suma de los n primeros números naturales
de forma paralela.
Hilo principal
S1 = 1+2+ … +50
S2 = 51+52+ … +100
suma_total = S1 + S2
Comunicación por memoria común
int suma_total = 0;
void suma_parcial(int ni, int nf) {
int j = 0;
int suma = 0;
for (j = ni; j <= nf; j++)
suma = suma + j;
suma_total = suma_total +
suma;
pthread_exit(0)
}
mov
mov
add
mov
reg1, suma_total
reg2, suma
reg1, reg2
suma_total, reg1
El problema de la sección crítica
●
●
●
Una sección crítica es una zona de código en
donde el proceso modifica variables o datos
comunes entre varios procesos.
Problemas potenciales: puede introducir condiciones
de carrera si no se adoptan las medidas
adecuadas.
Posible solución: sincronizar el acceso a los datos
(exclusión mútua).
El problema de la sección crítica
Formulación del problema de la sección crítica
●
●
●
Sean n procesos compitiendo para acceder a datos
compartidos
Cada proceso tiene una zona de código, denominada
sección crítica, en la que accede a los datos
compartidos.
Problema: encontrar un protocolo del tipo:
protocolo de entrada
sección CRÍTICA
protocolo de salida
sección RESTANTE
El problema de la sección crítica
Solución al problema de la sección crítica debe
satisfacer:
●
Exclusión mútua
●
Progreso
●
Espera limitada
Cada proceso se ejecuta a su propia velocidad, pero se
desconoce el orden de ejecución.
El problema de la sección crítica
Variables compartidas:
var turno : 0..1;
task Pi;
…
while turno <> i do no-op;
sección CRÍTICA
turno := j;
sección RESTANTE
…
task Pj;
end Pi;
…
while turno <> j do no-op;
sección CRÍTICA
turno := i;
sección RESTANTE
…
end Pi;
Soluciones por software
●
Pueden implementarlo procesos concurrentes que se
ejecuten en máquina monoprocesador o
multiprocesador con una memoria principal
compartida
●
No se require ningún soporte hardware
●
Soluciones:
●
Algoritmo de Dekker:
Algoritmo de exclusión mutua para dos procesos
Algoritmo de Peterson
➢
●
➢
Adaptación del algoritmo de Dekker
Soluciones por software
●
Primer intento: variable Turno
int turno = 0;
Proceso 0
. . .
Proceso 1
. . .
While (turno != 0)
/* no hacer nada */
SC0;
While (turno != 1)
/* no hacer nada */
SC1;
turno = 1;
. . .
turno = 0;
. . .
Soluciones por software
●
Segundo intento: Avisores
Boolean señal[2] = {false, false};
Proceso 0
Proceso 1
. . .
. . .
While (señal[1])
/* no hacer nada */
While (señal[0])
/* no hacer nada */
señal[0] = true;
SC0;
señal[0] = false;
. . .
señal[1] = true;
SC1;
señal[1] = false;
. . .
Soluciones por software
●
Tercer intento
Boolean señal[2] = {false, false};
Proceso 0
Proceso 1
. . .
señal[0] = true;
While (señal[1])
. . .
señal[1] = true;
While (señal[0])
/* no hacer nada */
SC0;
señal[0] = false;
. . .
/* no hacer nada */
SC1;
señal[1] = false;
. . .
Soluciones por software
●
Cuarto intento
Boolean señal[2] = {false, false};
Proceso 0
. . .
señal[0] = true;
While (señal[1]){
Señal[0] = false;
wait();
Señal[0] = true;
}
SC0;
señal[0] = false;
. . .
Proceso 1
. . .
señal[1] = true;
While (señal[0]){
Señal[0] = false;
wait();
Señal[0] = true;
}
SC1;
señal[1] = false;
. . .
Soluciones por hardware
●
Las soluciones hardware son soluciones a nivel de
instrucciones del lenguaje máquina:
●
Deshabilitación de interrupciones
●
Instrucción test_and_set (operación atómica).
●
Instrucción swap (operación atómica)
Soluciones por hardware
Deshabilitación de interrupciones
●
●
●
●
●
Las instrucciones de máquina que se utilizan son:
●
DI : Deshabilitar interrupciones
●
EI : Habilitar interrupciones
Se consigue la exclusión mutua inhibiendo los cambios de
contexto durante la SC.
Solución solo viable a nivel del núcleo del SO
La eficiencia puede verse afectada – capacidad del
procesador
No funciona en arquitectura multiprocesador.
Soluciones por hardware
Instrucción test and set
●
Permite comparar y fijar una variable atómicamente.
bool TS(int i)
{
if(i==0){
i = 1;
return true;
}
else {
return false;
}
}
Soluciones por hardware
Instrucción Swap
●
Permite intercambiar atómicamente dos variables.
void swap(int register, int memory)
{
int temp;
temp = memory;
Memory = register;
register = temp;
}
Soluciones por hardware
Soporte hardware para la SC
const int n= /*No.procesos*/;
int cerrojo
const int n= /*No. procesos*/;
void P(int i)
int cerrojo
{
void P(int i)
while(1)
{
{
int clavei;
while(!TS(cerrojo))
while(1)
/*No hacer nada*/
{
SC;
clavei = 1;
cerrojo = 0;
/* SR */
while(clavei != 0)
}
swap(clavei, cerrojo)
}
SC;
swap(clavei, cerrojo)
/* SR */
}
}
Soluciones por hardware
Ventajas
●
●
●
Desventajas
Aplicable para cualquier
número de procesos en
sistemas con memoria
compartida.
Es simple
verificar
y
fácil
de
Puede
usarse
para
soportar
múltiples
secciones críticas, cada
una con su propia
variable.
●
●
●
Se emplea espera activa
Puede
inanición
arbitraria
producirse
– selección
Puede
producirse
interbloqueo
–
Ejm:
proceso de baja prioridad
entra a la SC y es
interrumpido por uno de
mayor prioridad
Semáforos
Definición (Dijkstra):
●
Es una variable entera
●
●
Se inicializa con un valor no negativo
Sobre ella se definen dos operaciones o funciones
atómicas:
●
Espera (wait o P )
●
Señal (signal o V)
Semáforos
S: semaforo(N)
N >= 0
Espera
P(S)
{
S:=S-1;
if S<0 then
esperar(S);
}
Señal
V(S)
{
S:=S+1;
if S<=0 then
despertar(S);
}
La operación esperar(S) suspende al proceso que ha invocado
P() y lo introduce en una cola de espera asociada a S.
La operación despertar(S) extrae un proceso de la cola de
espera asociada a S y lo activa.
Semáforos
Solución al problema de la SC con semáforos
●
Los semáforos son un mecanismo de sincronización
Variables compartidas:
var mutex:semaforo(1); //vlr inicial 1
task Pi;
...
P(mutex);
sección CRÍTICA
V(mutex);
sección RESTANTE
...
end Pi;
Semáforos
Implementación
typedef struct {
int contador;
queueType *cola;
} Semaforo
Espera
void wait(semaforo s) {
s.contador--;
if (s.contador < 0) {
encola(s.cola, proActual);
bloquea();
}
}
Semáforos
Implementación
typedef struct {
int contador;
queueType *cola;
} Semaforo
Señal
void signal(semaforo s) {
s.contador++;
if (s.contador <= 0) {
P = sacar(s.cola);
despertar(P)
}
}
Semáforos
Semáforos
Implementación.
●
Espera activa:
●
●
El proceso que espera entrar en la sección crítica
“desaprovecha” el tiempo de CPU comprobando
cuando puede entrar (ejecutando las instrucciones del
protocolo de entrada).
Espera Pasiva:
●
●
La espera se realiza en la cola del semáforo, que es
una cola de procesos suspendidos.
El proceso que espera entrar en la sección crítica no
utiliza CPU; está suspendido.
Semáforos
Ejemplos de utilización
●
Un semáforo es un mecanismo de sincronización de
uso general:
➢
➢
Para conseguir exclusión mútua.
Para forzar relaciones de precedencia, como por
ejemplo:
●
El proceso Pj debe ejecutar B después de que el
proceso Pi haya ejecutado A.
Semáforos
var sinc: semaforo(0);
task Pi;
...
A;
V(sinc);
...
task Pj;
...
P(sinc)
B;
Semáforos
Problemas derivados de una utilización incorrecta
●
Interbloqueos: Hay un conjunto de procesos en el que
todos esperan (indefinidamente) un evento que sólo otro
proceso del conjunto puede producir. Ejemplo:
var s1: semaforo(1);
s2: semaforo(1);
task P1
...
P(s1);
P(s2);
...
V(s1);
V(s2);
task P2
...
P(s2);
P(s1);
...
V(s1);
V(s2);
Tuberias
●
●
Es un mecanismos de comunicación y sincronización
Conceptualmente, cada proceso ve la tubería como
un conducto con dos extremos
●
●
●
Un extremo → para escribir o insertar datos
y el otro extremo → para extraer o leer datos de la
tubería
El flujo de datos es unidireccional y FIFO ( extraen de
la tubería en el mismo orden en que se insertaron)
Tuberias
Comunicación Unidireccional
Tuberias
Comunicación Bidireccional
Mutex y variables condicionales
●
●
●
Son mecanismos de sincronización de hilos
Los mutex se emplean para obtener acceso exclusivo
a recursos compartidos y para asegurar la exclusión
mutua sobre la sección crítica
Es un semáforo binario con dos operaciones atómicas
●
●
lock(m) Intenta bloquear el mutex, si el mutex ya está
bloqueado el proceso se suspende
unlock(m) Desbloquea el mutex, si existen procesos
bloqueados en el mutex se desbloquea a uno.
lock(m) /* solicita la entrada en la sección crítica
<sección crítica>
unlock(m) /* salida de la sección crítica*/
Mutex y variables condicionales
Mutex y variables condicionales
●
Variables de sincronización asociadas a un mutex que
se utiliza para bloquear un proceso hasta que ocurra
algún suceso.
●
Conveniente ejecutarlas entre lock y unlock
●
Dos operaciones atómicas para esperar y señalizar
●
●
c_wait(): bloquea al proceso y le expulsa del mutex
dentro del cual se ejecuta y al que está asociada
la variable condicional
c_signal(): desbloquea a uno o varios procesos
suspendidos en la variable condicional.
Mutex y variables condicionales
Problemas clásicos de PC
●
Los productores y consumidores
●
Los lectores y escritores
●
Los cinco filósofos
Problemas clásicos de PC
●
Los productores y consumidores
●
Con buffer acotado
Problemas clásicos de PC
var buffer: array[0..n-1] of elemento;
entrada:=0, salida:=0, contador:= 0 : 0..n-1;
lleno: semaforo(0); vacio: semaforo(n), mutex: semaforo(1);
task productor;
var item: elemento;
repeat
item := producir();
P(vacio);
P(mutex);
buffer[entrada] := item;
entrada:=(entrada +1) mod n;
contador:=contador+1;
V(mutex);
V(lleno);
until false
end productor;
task consumidor;
var item: elemento;
repeat
P(lleno);
P(mutex);
item := buffer[salida]
salida := (salida +1) mod n;
contador:=contador-1;
V(mutex);
V(vacio);
consumir(item);
until false
end consumidor;
Problemas clásicos de PC
var buffer: array[0..n-1] of elemento;
entrada:=0, salida:=0, contador:= 0 : 0..n-1;
m:mutex, lleno, vacio: variable condicional
task productor;
var item: elemento;
repeat
item := producir();
lock(m);
while(contador==n)
c-wait(lleno,m);
buffer[entrada] := item;
entrada:=(entrada +1) mod n;
contador:=contador+1;
if(contador == 1)
c_signal(vacio);
unlock(m);
until false
end productor;
task consumidor;
var item: elemento;
repeat
lock(m);
while(contador==0)
c-wait(vacio,m);
item := buffer[salida]
salida := (salida +1) mod n;
contador:=contador-1;
if(contador== n-1)
c_signal(lleno);
unlock(m);
consumir(item);
until false
end consumidor;
Problemas clásicos de PC
●
Problema de los lectores y escritores
●
●
●
Hay un conjunto de datos comunes (un fichero, una
base de datos, etc.)
Los procesos lectores, acceden a los datos en
modo de sólo lectura
Los procesos escritores, acceden a los datos en
modo lectura-escritura
Problemas clásicos de PC
●
Problema de los lectores y escritores
●
Especificación del protocolo
Problemas clásicos de PC
●
Lectores y escritores (prioridad a los lectores)
Problemas clásicos de PC
●
Lectores y escritores (prioridad a los lectores)
var mutex: semaforo(1);
esc semaforo(1); nlectores:=0 : integer;
task escritor;
...
P(esc);
escribir();
V(esc);
. . .
end escritor;
task lector;
…
P(mutex);
nlectores :=
if nlectores
V(mutex);
leer();
P(mutex);
nlectores :=
if nlectores
V(mutex);
…
end lector;
nlectores + 1;
= 1 then P(esc);
nlectores - 1;
= 0 then V(esc);
Problemas clásicos de PC
●
Lectores y escritores (prioridad a los
escritores)
Problemas clásicos de PC
var mutexE, mutexL, Esem, Lsem,z : semaforo(1);
nlectores:=0, nescritores:=0 : integer;
task lector;
while(true){
P(z);
P(Lsem);
P(mutexL);
nlectores++;
if nlectores==1 then
P(Esem);
V(mutexL);
V(Lsem);
V(z);
Leer_Unidad
P(mutexL);
nlectores--;
if nlectores==0 then
V(Esem);
V(mutexL);
}
end lector;
task escritor;
while(true){
P(mutexE);
nescritores++;
if nescritores==1 then
P(Lsem);
V(mutexE);
P(Esem);
Escribir_Unidad;
V(Esem);
P(mutexE);
nescritores--;
if nescritores==0 then
V(Lsem);
V(mutexE);
}
end escritor;
Comunicación por mensajes
Pasos de mensajes
●
●
●
●
Los sistemas de mensajes permiten la comunicación
entre procesos con espacios de direcciones
distintos, bien sea locales y remotos
Permite resolver la exclusión mutua
Sincronizar entre un proceso que recibe un mensaje y
otro que lo envía
Hay dos operaciones básicas
●
●
send(destino, mensaje): enviar un mensaje a un
destino
receive(origen, mensaje): recibir un mensaje de un
origen
Comunicación por mensajes
Aspectos de diseño relativos a este tipo de sistemas
1. Tamaño del mensaje:
➔
➔
Fija: más sencilla, pero obliga a descomponer los
mensajes grandes en mensajes de longitud fija más
pequeños.
Variable
2. Flujo de datos: de acuerdo al flujo de datos la
comunicación puede ser:
➔
Comunicación Unidireccional:
➔
Comunicación bidireccional:
Comunicación por mensajes
3. Comunicación: según el modo de nombrar el origen y
el destino esta puede ser:
➢
Comunicación directa:
➢
➢
➢
➢
send(P, mensaje)
receive(Q, mensaje)
receive(ANY, mensaje)
Comunicación Indirecta:
➢
una estructura de datos: colas de mensajes o puertos
Comunicación por mensajes
●
Comunicación Indirecta:
–
–
send(Q, mensaje)
receive(Q, mensaje)
Comunicación por mensajes
Comunicación por mensajes
4. Sincronización
●
Al ejecutar la primitiva send, hay dos posibilidades
➢
➢
●
El emisor se bloquea hasta que se recibe el mensaje
El emisor no se bloquea
Al ejecutar la primitiva receive, también hay dos
posibilidades
➢
➢
Si hay un mensaje enviado, se recibe el mensaje y se
continua la ejecución
Si no hay ningún mensaje esperando, entonces, el
proceso se bloquea hasta que llegue un mensaje o el
proceso continua abandonando el intento de recepción
de mensaje.
Comunicación por mensajes
4. Sincronización
●
●
Los emisores y receptores pueden ser bloqueantes o
no bloqueantes
Tres combinaciones:
➔
Envío bloqueante, recepción bloqueante
●
●
➔
Emisor y el receptor se bloquean hasta que se entrega el
mensaje
Es una técnica totalmente sincrona, conocida como cita
Envío no bloqueante, recepción no bloqueante
●
●
El emisor puede continuar, pero el receptor está bloqueado
esperando el mensaje
más utilizada → estilo servidor
Comunicación por mensajes
4. Sincronización
●
Tres combinaciones:
➔
Envío no bloqueante, recepción no bloqueante
●
●
●
Ninguno debe esperar
Totalmente asincrona
Es necesario disponer de servicios que permitan al
receptor saber si se ha recibido un mensaje.
Comunicación por mensajes
5. Almacenamiento
●
Hace referencia a la capacidad del enlace de
comunicaciones. Pueden ser:
➔
➔
➔
➔
No tener capacidad (sin almacenamiento) para
almacenar mensajes.
Tener capacidad (con almacenamiento) para almacenar
mensajes.
Si la cola no esta llena entonces el emisor puede
continuar su ejecución
Sino el emisor se bloqueará.
Comunicación por mensajes
Solución al problema de productores y consumidores
task productor;
var item : elemento;
repeat
item := producir();
send( consumidor, item );
until false;
end productor;
task consumidor;
var item : elemento;
repeat
receive( productor, item );
consumir(item);
until false;
end consumidor;
Comunicación directa
Comunicación sincrona
Descargar