PROGRAMACIÓN CONCURRENTE

Anuncio
PROGRAMACIÓN
CONCURRENTE
Lenguajes de Programación - Progr. Concurrente
1
Introducción
El concepto fundamental de la programación concurrente es la
noción de Proceso.
Proceso: Cálculo secuencial con su propio flujo de control.
La concurrencia en software implica la existencia de diversos
flujos de control en un mismo programa colaborando para
resolver un problema.
Lenguajes de Programación - Progr. Concurrente
2
1
Procesos vs. Hilos
En el contexto del Sistema Operativo, un Proceso es una
instancia de un Programa que está siendo ejecutado en el
ordenador.
Proceso = Código de programa + Datos + Recursos
Un S.O. admite concurrencia si es capaz de manejar diversos
procesos simultáneamente.
En el contexto de un Programa concurrente, un Hilo (Thread)
es cada uno de los flujos secuenciales de control
independientes especificados en el programa.
Lenguajes de Programación - Progr. Concurrente
3
Procesos Secuenciales
Un proceso tradicional, correspondiente a un programa
secuencial, es un proceso que posee un único hilo de control.
Unflujo
flujo(camino)
(camino)de
decontrol
control
Un
El
Elcontador
contadorde
deprograma,
programa,elel
estado
de
la
pila
estado de la pilayyde
delos
los
objetos
objetosdefinen
definenelelestado
estado
del
delsistema.
sistema.
Lenguajes de Programación - Progr. Concurrente
4
2
Procesos Concurrentes
Un programa concurrente da lugar, durante su ejecución, a un
proceso con varios hilos de ejecución.
Variosflujos
flujos(caminos)
(caminos)de
de
Varios
control
control
Lenguajes de Programación - Progr. Concurrente
5
Elegir sitio
Contratar arquitecto
Desarrollar plano
Ofertar plano
[no aceptado]
[aceptado]
Realizar trabajo en el terreno
Hacer trabajo comercial()
Terminar construcción
Lenguajes de Programación - Progr. Concurrente
6
3
Concurrencia Software vs. Paralelismo Hardware
La concurrencia software es un concepto lógico, no implica la
existencia de paralelismo en el hardware:
9 Las operaciones hardware ocurren en paralelo si ocurren al
mismo tiempo.
9 Las operaciones (software) en un programa son concurrentes si
pueden ejecutarse en paralelo, aunque no necesariamente
deben ejecutarse así.
Lenguajes de Programación - Progr. Concurrente
7
Tipos de concurrencia
Concurrencia Física:
9 Existe más de un procesador y varias unidades (hilos) de un
mismo programa se ejecutan realmente de forma simultánea.
Concurrencia Lógica:
9 Asumir la existencia de varios procesadores, aunque no existan
físicamente. El implementador de tareas del lenguaje se
encargará de “mapear” la concurrencia lógica sobre el hardware
realmente disponible.
La concurrencia lógica es más general, pues el diseño del
programa no está condicionado por los recursos de
computación disponibles.
Lenguajes de Programación - Progr. Concurrente
8
4
Arquitecturas Multiprocesador: Revisión histórica
Años 50: Primeras máquinas con varios procesadores
9 Un procesador de propósito general y varios procesadores para
controlar la E/S.
9 Permitían ejecutar un programa mientras se realizaba E o S
para otros programas.
9 No se puede hablar de ejecución concurrente de programas.
Años 60 (inicio): Primeras multiproc. reales
9 El programador de tareas del SO distribuía programas entre los
procesadores a partir de una cola de trabajos.
9 Permitían concurrencia a nivel de programas.
Lenguajes de Programación - Progr. Concurrente
9
Arquitecturas Multiprocesador (2)
Años 60 (mitad): Ordenadores con hardware específico
múltiple
9 Multiplican el número de multiplicadores en coma flotante o
unidades aritméticas en coma flotante completas.
9 Estas unidades ejecutan instrucciones procedentes de un único
flujo de instrucciones (programa).
9 Los compiladores determinaban qué instrucciones podían
ejecutarse concurrentemente.
Lenguajes de Programación - Progr. Concurrente
10
5
Arquitecturas Multiprocesador: Categorías
SIMD (Single Instruction Múltiple Data):
9 Pueden ejecutar simultáneamente la misma instrucción sobre
diferentes conjuntos de datos.
9 Cada procesador tiene su propia memoria local.
9 Hay un procesador que controla el trabajo del resto.
9 Como se ejecuta la misma instrucción no es preciso ningún tipo
de sincronización entre tareas.
9 Máquinas típicas: los procesadores vectoriales
• Específicas para trabajar con datos almacenados en arrays.
• Aplicación en cálculo científico.
Lenguajes de Programación - Progr. Concurrente
11
Arquitecturas Multiprocesador: Categorías (2)
MIMD (Multiple Instruction Multiple Data)
9 Cada procesador ejecuta su propio flujo de instrucciones.
9 Es preciso poder sincronizar tareas.
9 Dos tipos de configuración:
• Memoria compartida.
• Memoria distribuida.
9 Hay que sincronizar el acceso a los datos.
9 Soportan concurrencia a nivel de hilos dentro del programa.
Lenguajes de Programación - Progr. Concurrente
12
6
Concurrencia en un Programa
Desde el punto de vista de la programación, interesa la
concurrencia lógica que puede existir en el interior de un
programa.
Un Lenguaje de Programación será concurrente si posee las
estructuras necesarias para definir y manejar diferentes tareas
(hilos de ejecución) dentro de un programa.
9 Ejemplos: Java, Ada
El compilador y el SO serán los responsables de “mapear” la
concurrencia lógica del programa sobre el hardware disponible.
Lenguajes de Programación - Progr. Concurrente
13
Sincronización de tareas
La Sincronización es el mecanismo que controla el orden en
que se ejecutan las tareas.
Tipos de Sincronización:
9 Cooperación:
• La tarea A debe de esperar que la tarea B finalice alguna
actividad para poder continuar con su ejecución.
9 Competición:
• La tarea A necesita acceder a un dato x mientras la tarea B
está accediendo al mismo. La tarea A debe de esperar a
que la tarea B finalice su uso de x para poder continuar.
Lenguajes de Programación - Progr. Concurrente
14
7
Necesidad de Sincronización (ejemplo)
Ejemplo de Competición:
9 Sea un dato TOTAL que inicialmente tiene el valor 3.
• La tarea A realiza: TOTAL++;
• La tarea B realiza: TOTAL *= 2;
9 Cada tarea completa su operación sobre TOTAL realizando los
siguientes pasos:
• Recuperar el valor de TOTAL
• Realizar una operación aritmética
• Almacenar el nuevo valor de TOTAL
Lenguajes de Programación - Progr. Concurrente
15
Sincronización para Competición (ejemplo)
Si no existe sincronización entre las tareas A y B, se pueden
dar cuatro resultados diferentes (TOTAL = 3):
9 Correctos:
La tarea A completa su operación antes de que empiece B:
• Resultado final, TOTAL = 8
La tarea B completa su operación antes de que empiece A:
• Resultado final, TOTAL = 7
9 Incorrectos:
Las tareas A y B recuperan el valor de TOTAL sin que ninguna
haya llegado a almacenar el nuevo valor:
• Resultado final, TOTAL = 6. Si la última en finalizar es B.
• Resultado final, TOTAL = 4. Si la última en finalizar es A.
Lenguajes de Programación - Progr. Concurrente
16
8
Sincronización (Ejemplo)
Memoria
Registro1
Registro2
TOTAL
3
Lenguajes de Programación - Progr. Concurrente
17
Sincronización (Ejemplo: A antes que B)
Memoria
Registro1
Registro2
TOTAL
3
Hilo A Æ TOTAL ++
Lenguajes de Programación - Progr. Concurrente
18
9
Sincronización (Ejemplo: A antes que B)
Memoria
Registro1
Registro2
3
TOTAL
3
Hilo A Æ TOTAL ++
(i) Recuperar (TOTAL)
Lenguajes de Programación - Progr. Concurrente
19
Sincronización (Ejemplo: A antes que B)
Memoria
Registro1
TOTAL
Registro2
4
3
Hilo A Æ TOTAL ++
(i) Recuperar (TOTAL)
(ii) Sumar 1
Lenguajes de Programación - Progr. Concurrente
20
10
Sincronización (Ejemplo: A antes que B)
Memoria
TOTAL
Registro1
Registro2
4
4
Hilo A Æ TOTAL ++
(i) Recuperar (TOTAL)
(ii) Sumar 1
(iii) Almacenar (TOTAL)
Lenguajes de Programación - Progr. Concurrente
21
Sincronización (Ejemplo: A antes que B)
Memoria
TOTAL
Registro1
Registro2
4
4
Hilo A Æ TOTAL ++
(i) Recuperar (TOTAL)
(ii) Sumar 1
(iii) Almacenar (TOTAL)
Hilo B Æ TOTAL *=2
Lenguajes de Programación - Progr. Concurrente
22
11
Sincronización (Ejemplo: A antes que B)
Memoria
TOTAL
Registro1
Registro2
4
4
4
Hilo A Æ TOTAL ++
(i) Recuperar (TOTAL)
(ii) Sumar 1
(iii) Almacenar (TOTAL)
Hilo B Æ TOTAL *=2
(i) Recuperar (TOTAL)
Lenguajes de Programación - Progr. Concurrente
23
Sincronización (Ejemplo: A antes que B)
Memoria
TOTAL
Registro1
Registro2
4
8
4
Hilo A Æ TOTAL ++
(i) Recuperar (TOTAL)
(ii) Sumar 1
(iii) Almacenar (TOTAL)
Hilo B Æ TOTAL *=2
(i) Recuperar (TOTAL)
(ii) Multiplicar x 2
Lenguajes de Programación - Progr. Concurrente
24
12
Sincronización (Ejemplo: A antes que B)
Memoria
TOTAL
Registro1
Registro2
4
8
8
Hilo A Æ TOTAL ++
(i) Recuperar (TOTAL)
(ii) Sumar 1
(iii) Almacenar (TOTAL)
Hilo B Æ TOTAL *=2
(i) Recuperar (TOTAL)
(ii) Multiplicar x 2
(iii) Almacenar (TOTAL)
Lenguajes de Programación - Progr. Concurrente
25
Sincronización (Ejemplo)
Memoria
Registro1
Registro2
TOTAL
3
Lenguajes de Programación - Progr. Concurrente
26
13
Sincronización (Ejemplo: B interfiere con A )
Memoria
Registro1
Registro2
TOTAL
3
Hilo A Æ TOTAL ++
Lenguajes de Programación - Progr. Concurrente
27
Sincronización (Ejemplo: B interfiere con A )
Memoria
Registro1
TOTAL
Registro2
3
3
Hilo A Æ TOTAL ++
(i) Recuperar (TOTAL)
Lenguajes de Programación - Progr. Concurrente
28
14
Sincronización (Ejemplo: B interfiere con A )
Memoria
Registro1
Registro2
3
3
TOTAL
3
Hilo A Æ TOTAL ++
(i) Recuperar (TOTAL)
Hilo B Æ TOTAL *=2
(i) Recuperar (TOTAL)
Lenguajes de Programación - Progr. Concurrente
29
Sincronización (Ejemplo: B interfiere con A )
Memoria
Registro1
Registro2
4
3
TOTAL
3
Hilo A Æ TOTAL ++
(i) Recuperar (TOTAL)
(ii) Sumar 1
Hilo B Æ TOTAL *=2
(i) Recuperar (TOTAL)
Lenguajes de Programación - Progr. Concurrente
30
15
Sincronización (Ejemplo: B interfiere con A )
Memoria
Registro1
Registro2
4
6
TOTAL
3
Hilo A Æ TOTAL ++
(i) Recuperar (TOTAL)
(ii) Sumar 1
Hilo B Æ TOTAL *=2
(i) Recuperar (TOTAL)
(ii) Multiplicar x 2
Lenguajes de Programación - Progr. Concurrente
31
Sincronización (Ejemplo: B interfiere con A )
Memoria
TOTAL
Registro1
Registro2
4
6
4
Hilo A Æ TOTAL ++
(i) Recuperar (TOTAL)
(ii) Sumar 1
(iii) Almacenar (TOTAL)
Hilo B Æ TOTAL *=2
(i) Recuperar (TOTAL)
(ii) Multiplicar x 2
Lenguajes de Programación - Progr. Concurrente
32
16
Sincronización (Ejemplo: B interfiere con A )
Memoria
Registro1
Registro2
4
6
TOTAL
6
Hilo A Æ TOTAL ++
(i) Recuperar (TOTAL)
(ii) Sumar 1
(iii) Almacenar (TOTAL)
Hilo B Æ TOTAL *=2
(i) Recuperar (TOTAL)
(ii) Multiplicar x 2
(iii) Almacenar (TOTAL)
Lenguajes de Programación - Progr. Concurrente
33
Sincronización para Competición (ejemplo)
Tarea A
TOTAL ++;
Recuperar (TOTAL)
Sumar 1
Almacenar (TOTAL)
Recuperar (TOTAL)
Inicio
Sumar 1
TOTAL
Almacenar (TOTAL)
3
Lenguajes de Programación - Progr. Concurrente
Fin
6
Recuperar (TOTAL)
Multiplicar por 2
Almacenar (TOTAL)
Tarea B
TOTAL *= 2;
Recuperar (TOTAL)
4
Multiplicar
por 2
Almacenar (TOTAL)
34
17
Diseño de lenguajes Concurrentes
Los principales conceptos que debe incorporar un lenguaje de
programación que soporte Concurrencia son:
9 ¿Cómo se soporta la sincronización para Cooperación?
9 ¿Cómo se soporta la sincronización para Competición?
9 ¿Cómo y cuándo se inicia y finaliza la ejecución de tareas?
9 ¿Las tareas se crean estática o dinámicamente?
Lenguajes de Programación - Progr. Concurrente
35
Semáforos
Dijkstra, 1965.
Un semáforo es una estructura de datos que consiste en:
9 Un valor entero.
9 Una cola de tareas (descriptores):
• Los descriptores de tareas almacenan la información
relevante sobre el estado de ejecución de la tarea.
Para establecer limitación de acceso a los datos, se establecen
protecciones (semáforo) en las operaciones de acceso a
dichos datos.
Las protecciones (semáforos) deben permitir acceder a los
datos sólo a una tarea en un instante determinado.
Lenguajes de Programación - Progr. Concurrente
36
18
Semáforos (2)
Una parte importante del mecanismo de protección consiste
en asegurar que todos los intentos de acceso a los datos
protegidos se llevarán a cabo en algún momento:
9 Cola de tareas.
Las únicas operaciones permitidas en los semáforos son:
9 P (del holandés passeren): esperar
9 V (del holandés vrygeren): avisar
Lenguajes de Programación - Progr. Concurrente
37
Ejemplo de Sincronización para Cooperación
Los datos compartidos están en un buffer (situación habitual).
Operaciones de acceso al buffer:
9 ALMACENAR
9 EXTRAER
Hay 2 tareas que acceden al buffer para Cooperar:
9 Siguen el esquema Productor-Consumidor:
• Una tarea produce datos y los almacena en el buffer.
• La segunda tarea requiere datos y los extrae del buffer.
Lenguajes de Programación - Progr. Concurrente
38
19
Ejemplo (2, sin sincronización)
Versión no sincronizada de las tareas:
Tarea Productor:
while ()
{
//generar valor...
buffer.almacenar (valor);
}
Fin_tarea
Tarea Consumidor:
while ()
{
valor = buffer.extraer ();
//utilizar valor...
}
Fin_tarea
Problemas:
9 El Productor genera valores más rápidamente de lo que los
consume el Consumidor Æ el buffer se llena.
9 El Consumidor requiere valores más rápidamente de lo que los
produce el Productor Æ el buffer se vacía.
Lenguajes de Programación - Progr. Concurrente
39
Ejemplo (2, con sincronización)
Versión sincronizada con semáforos de las tareas:
Tarea Productor:
while ()
{
//generar valor...
esperar (posLibres);
buffer.almacenar (valor);
avisar (posOcupadas);
}
Fin_tarea
Esperaaaque
queexistan
existan
Espera
posiciones
libres
enelel
posiciones libres en
buffer,
mientras
tanto
la
buffer, mientras tanto la
tareaestá
estábloqueada.
bloqueada.
tarea
Lenguajes de Programación - Progr. Concurrente
Tarea Consumidor:
while ()
{
esperar (posOcupadas);
valor = buffer.extraer ();
avisar (posLibres);
//utilizar valor...
}
Fin_tarea
Esperaaaque
queexistan
existan
Espera
posiciones
ocupadas
enelel
posiciones ocupadas en
buffer,
mientras
tanto
la
buffer, mientras tanto la
tareaestá
estábloqueada.
bloqueada.
tarea
40
20
Ejemplo (3)
Hay 2 aspectos a proteger sobre el acceso al buffer:
9 posLibres (necesaria para el Productor)
9 posOcupadas (necesaria para el Consumidor)
Se realiza la protección mediante 2 semáforos:
class Semaforo {
private int cont;
private ColaTareas cola;
public esperar ();
public avisar ();
}
posLibres
posOcupadas
Lenguajes de Programación - Progr. Concurrente
41
Ejemplo (4)
posLibres:
cont Æ cuantas posiciones libres hay disponibles en el buffer
cola Æ las tareas que están esperando poder almacenar datos en el buffer
posOcupadas:
cont Æ cuantas posiciones ocupadas (datos) hay disponibles en el buffer
cola Æ las tareas que están esperando poder extraer datos en el buffer
Lenguajes de Programación - Progr. Concurrente
42
21
Esperar / Avisar
esperar () {
if ( this.cont > 0 ) this.cont --;
// correcto hay disponibilidad, decremento cont
// p.q. se va a realizar 1 operación protegida
else
this.cola.insertar (tarea que invoca esperar);
// no hay disponibilidad, encolar la tarea para
// continuar con ella cuando sea posible
}
avisar () {
if ( this.cola.esVacia() ) this.cont ++;
// no hay tareas esperando este aviso,
// incremento la disponibilidad
else
return ( this.cola.extraer () );
// había tareas esperando, extraer la primera
}
Lenguajes de Programación - Progr. Concurrente
43
Interpretación de las tareas
Tarea Productor:
while ()
{
//generar valor...
posLibres.esperar();
buffer.almacenar (valor);
posOcupadas.avisar();
}
Fin_tarea
Tarea Consumidor:
while ()
{
posOcupadas.esperar();
valor = buffer.extraer ();
posLibres.avisar();
//utilizar valor...
}
Fin_tarea
Lenguajes de Programación - Progr. Concurrente
¿haydisponibilidad
disponibilidadde
deposiciones
posicioneslibres?
libres?
¿hay
SI:lalatarea
tareacontinúa.
continúa.
SI:
NO:elelProductor
Productorse
seguarda
guardaen
enlalacola
cola
NO:
avisode
deque
quehay
hayuna
unanueva
nuevaposición
posiciónocupada.
ocupada.
aviso
Sihabía
habíatareas
tareasesperando
esperandodatos,
datos,una
unatarea
tareade
de
Si
colapodrá
podrácontinuar.
continuar.
lalacola
¿haydisponibilidad
disponibilidadde
dedatos?
datos?
¿hay
SI:
la
tarea
continúa.
SI: la tarea continúa.
NO:elelConsumidor
Consumidorse
seguarda
guardaen
enlalacola
cola
NO:
avisode
deque
quehay
hayuna
unanueva
nuevaposición
posiciónlibre.
libre.
aviso
Sihabía
habíatareas
tareasesperando
esperandoguardar
guardardatos,
datos,una
una
Si
tareade
delalacola
colapodrá
podrácontinuar.
continuar.
tarea
44
22
Interpretación gráfica
buffer
X X X X X X X X
posLibres
avisar
esperar
Almacenar
Productor
posOcupadas
avisar
esperar
Consumidor
Extraer
Lenguajes de Programación - Progr. Concurrente
45
Ejemplo de Sincronización para Competición
Controlar el acceso al buffer: sólo una tarea puede estar
usándolo.
Un semáforo para controlar el acceso:
9 cont: no necesita contar nada, sólo debe indicar si se está
usando el buffer (0) o no (1) Æ Semáforo Binario.
9 esperar: da permiso para acceder sólo si cont == 1
Podemos añadir un nuevo semáforo al ejemplo anterior para
controlar el acceso exclusivo al buffer (acceso).
Lenguajes de Programación - Progr. Concurrente
46
23
Revisión de las tareas
Tarea Productor:
while ()
{
//generar valor...
posLibres.esperar();
acceso.esperar();
buffer.almacenar (valor);
acceso.avisar();
posOcupadas.avisar();
}
Fin_tarea
Tarea Consumidor:
while ()
{
posOcupadas.esperar();
acceso.esperar();
valor = buffer.extraer ();
acceso.avisar();
posLibres.avisar();
//utilizar valor...
}
Fin_tarea
¿disponibilidad libres/ocupadas?
¿puedo acceder?
ACCESO
he accedido
hay disponibilidad ocupadas/libres
Lenguajes de Programación - Progr. Concurrente
47
Semáforos (fin)
Problema: Los semáforos son en sí mismos un recurso
9 Varias
tareas
están
solicitando
operaciones
esperar/avisar al semáforo Æ ¿Ponemos un semáforo
al semáforo?
Solución: las tareas de un semáforo no se pueden interrumpir.
PL/I: Concurrencia con semáforos binarios.
ALGOL 68: Concurrencia con semáforos.
Lenguajes de Programación - Progr. Concurrente
48
24
Monitores
Hoare, 1974.
Monitor = Encapsula datos + mecanismos de sincronización.
Solución de más alto nivel que los semáforos.
Si el problema es sincronizar el acceso de tareas a datos
comunes Æ que sean los propios datos los que se encarguen
del sincronismo.
Los lenguajes que soportan monitores aseguran el uso
excluyente del monitor:
9 No hay que controlar la sincronización para Competición.
Concurrent Pascal y Modula incorporan monitores como tipo.
Lenguajes de Programación - Progr. Concurrente
49
Estructura de un monitor
class bufferMonitor {
private buffer;
//incluir todas las declaraciones para implementar
//el buffer (array, lista circular, etc...)
//incluir estructuras para sincronizar la
Elacceso
acceso(Competición)
(Competición)lo
lo
//Cooperación de tareas.
El
controlaelelcompilador.
compilador.
private ColaTareas leer, escribir;
controla
public void almacenar ( valor x ) {...}
public valor extraer () {...}
Laimplementación
implementacióndebe
debede
de
La
incluirlalasincronización.
sincronización.
incluir
}
Tarea Productor:
while ()
{
//generar valor...
bufferMonitor.almacenar (valor);
}
Fin_tarea
Lenguajes de Programación - Progr. Concurrente
Tarea Consumidor:
while ()
{
valor = bufferMonitor.extraer ();
//utilizar valor...
}
Fin_tarea
50
25
Almacenar/Extraer
void almacenar ( valor x ) {
if ( buffer.esLleno() )
escribir.delay();
buffer.insertar (x);
leer.continue();
}
Sebloquea
bloquea(y
(yencola)
encola)lalatarea
tarea
Se
queusa
usaalmacenar
almacenarÆ
Æse
selele
que
quitalalaexclusividad
exclusividadde
de
quita
acceso
hasta
que
pueda
acceso hasta que pueda
continuar.
continuar.
Secontinúa
continúacon
conalguna
algunatarea
tarea
Se
que
esté
esperando
leer.
que esté esperando leer.
void extraer ( valor x ) {
if ( buffer.esVacio() )
leer.delay();
x = buffer.eliminar ();
escribir.continue();
}
Lenguajes de Programación - Progr. Concurrente
51
delay/continue
delay:
9 La tarea que ejecuta delay se bloquea y se añade a la cola.
9 Se le quita el acceso exclusivo al monitor
9 El monitor está disponible para otra tarea
continue:
9 Desconecta del monitor a la tarea que lo ejecuta.
9 El monitor está disponible para otra tarea.
9 Si la cola contiene alguna tarea, extrae una tarea y reanuda su
ejecución (que había sido detenida por un delay).
Lenguajes de Programación - Progr. Concurrente
52
26
Descargar