Sistemas Concurrentes y Distribuidos.
Gu´ apuntes, problemas, seminarios y pr´cticas.
ıa,
a
Curso 2013-14

1
2
Contents
I

Gu´ de la asignatura
ıa

9

1 Gu´ de la asignatura
ıa
1.1

Datos generales . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 11

1.4

Bibliograf´ . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 16
ıa

1.2
1.3

II

11

Objetivos y temario . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 12

Metodolog´ docente y evaluaci´n . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 13
ıa
o

Apuntes de teor´
ıa

19

2 Tema 1. Introducci´n.
o
2.1
2.2
2.3
2.4
2.5
2.6

21

Conceptos b´sicos y motivaci´n . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 21
a
o

2.1.1

Conceptos b´sicos relacionados con la concurrencia . . . . . . . . . . . . . . . . . . . . . . 21
a

2.2.1

Consideraciones sobre el hardware . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 22

2.1.2

Motivaci´n de la Programaci´n concurrente . . . . . . . . . . . . . . . . . . . . . . . . . . . . 22
o
o

Modelo abstracto y consideraciones sobre el hardware . . . . . . . . . . . . . . . . . . . . . . . . . 22

2.2.2

Modelo Abstracto de concurrencia . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 25

Exclusi´n mutua y sincronizaci´n . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 30
o
o

2.3.1
2.3.2

Concepto de exclusi´n mutua . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 31
o

Condici´n de sincronizaci´n . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 32
o
o

Propiedades de los sistemas concurrentes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 33

2.4.1
2.4.2

Correcci´n de un sistema concurrente . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 33
o
Propiedades de seguridad y vivacidad . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 34

Verificaci´n de programas concurrentes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 35
o

2.5.1
2.5.2

Verificaci´n de programas concurrentes. Introducci´n . . . . . . . . . . . . . . . . . . . . . . 35
o
o

Enfoque axiom´tico para la verificaci´n . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 35
a
o

Problemas del tema 1. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 36

3 Tema 2. Sincronizaci´n en memoria compartida.
o
3.1

43

Introducci´n a la sincronizaci´n en memoria compartida. . . . . . . . . . . . . . . . . . . . . . . . . . 43
o
o
3
CONTENTS
3.2

3.3

3.1.1

Estructura de los procesos con Secciones Cr´
ıticas . . . . . . . . . . . . . . . . . . . . . . . . 44

3.2.1

Refinamiento sucesivo de Dijkstra . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 47

3.1.2

3.5

3.2.2
3.2.3
3.2.4

Algoritmo de Dekker . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 51
Algoritmo de Peterson . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 52
Algoritmo de Peterson para n procesos. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 54

Soluciones hardware con espera ocupada (cerrojos) para E.M. . . . . . . . . . . . . . . . . . . . . . 56

3.3.1

Introducci´n . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 56
o

3.3.4

Desventajas de los cerrojos. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 59

3.3.2
3.3.5

La instrucci´n LeerAsignar. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 57
o
La instrucci´n Intercambia. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 58
o
Uso de los cerrojos. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 60

Sem´foros para sincronizaci´n . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 60
a
o

3.4.1
3.4.2
3.4.3
3.4.4

Introducci´n . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 60
o

Estructura de un sem´foro . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 61
a
Operaciones sobre los sem´foros. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 61
a

Uso de los sem´foros . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 62
a

Monitores como mecanismo de alto nivel . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 63

3.5.1
3.5.2
3.5.3
3.5.4
3.5.5

3.6

Propiedades para exclusi´n mutua . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 45
o

Soluciones software con espera ocupada para E.M. . . . . . . . . . . . . . . . . . . . . . . . . . . . . 46

3.3.3
3.4

CONTENTS

3.5.6
3.5.7

Fundamento te´rico de los monitores . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 63
o

Definici´n de monitor . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 64
o
Funcionamiento de los monitores . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 67

Sincronizaci´n en monitores . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 69
o
Sem´ntica de las se˜ales de los monitores . . . . . . . . . . . . . . . . . . . . . . . . . . . . 74
a
n

Implementaci´n de monitores . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 78
o

Verificaci´n de monitores . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 79
o

Problemas del tema 2. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 80

4 Tema 3. Sistemas basados en paso de mensajes.
4.1

4.2

93

Mecanismos b´sicos en sistemas basados en paso de mensajes . . . . . . . . . . . . . . . . . . . . 93
a

4.1.1

Introducci´n . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 93
o

4.1.4

Espera selectiva . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 106

4.1.2
4.1.3

Vista logica arquitectura y modelo de ejecuci´n . . . . . . . . . . . . . . . . . . . . . . . . . 94
o

Primitivas b´sicas de paso de mensajes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 95
a

Paradigmas de interacci´n de procesos en programas distribuidos . . . . . . . . . . . . . . . . . . 111
o

4.2.1
4.2.2
4.2.3

Introducci´n . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 111
o

Maestro-Esclavo . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 111
Iteraci´n s´
o ıncrona . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 113
4
CONTENTS
4.3

4.4

CONTENTS

4.2.4

Encauzamiento (pipelining) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 115

4.3.2

El paradigma Cliente-Servidor . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 117

Mecanismos de alto nivel en sistemas distribuidos . . . . . . . . . . . . . . . . . . . . . . . . . . . . 116

4.3.1
4.3.3
4.3.4

Introducci´n . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 116
o
Llamada a Procedimiento (RPC) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 118
Java Remote Method Invocation (RMI) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 120

Problemas del tema 3. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 128

5 Tema 4. Introducci´n a los sistemas de tiempo real.
o
5.1
5.2

III

Concepto de sistema de tiempo real. Medidas de tiempo y modelo de tareas. . . . . . . . . . . . 133

5.1.1
5.1.2
5.1.3

Definici´n, tipos y ejemplos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 133
o
Propiedades de los Sistemas de Tiempo Real . . . . . . . . . . . . . . . . . . . . . . . . . . 136

Modelo de Tareas . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 138

Esquemas de planificaci´n . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 142
o

5.2.1
5.2.2

Planificaci´n C´
o ıclica. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 143
Planificaci´n con prioridades . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 145
o

Seminarios y guiones de pr´cticas
a

6 Seminario 1. Programaci´n multihebra y sincronizaci´n con sem´foros.
o
o
a
6.1
6.2

6.4

7.2

151

Hebras POSIX . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 154

6.2.1

Introducci´n . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 154
o

6.2.4

Par´metros e identificaci´n de hebras . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 158
a
o

6.2.2
6.2.5

Creaci´n y finalizaci´n de hebras . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 155
o
o

Sincronizaci´n mediante uni´n . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 157
o
o
Ejemplo de hebras: c´lculo num´rico de integrales . . . . . . . . . . . . . . . . . . . . . . . 159
a
e

Introducci´n a los Sem´foros . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 163
o
a
Sincronizaci´n de hebras con sem´foros POSIX . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 165
o
a

6.4.1
6.4.2
6.4.3

Funciones b´sicas. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 165
a
Exclusi´n mutua . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 167
o
Sincronizaci´n . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 168
o

7 Pr´ctica 1. Sincronizaci´n de hebras con sem´foros.
a
o
a
7.1

149

Concepto e Implementaciones de Hebras . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 151

6.2.3
6.3

133

171

Objetivos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 171

El problema del productor-consumidor . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 171
7.2.1
7.2.2

Descripci´n del problema. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 171
o
Plantillas de c´digo . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 172
o
5
CONTENTS
7.3

CONTENTS

7.2.3

Actividades y documentaci´n . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 174
o

7.3.2

Plantillas de c´digo . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 176
o

El problema de los fumadores. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 175

7.3.1
7.3.3

Descripci´n del problema. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 175
o
Actividades y documentaci´n. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 176
o

8 Seminario 2. Hebras en Java.
8.1
8.2
8.3
8.4
8.5
8.6

179

Hebras en Java . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 180

Creaci´n de hebras en Java . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 180
o
Estados de una hebra Java . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 182
Prioridades y planificaci´n. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 184
o

8.4.1

Un ejemplo m´s completo . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 184
a

8.5.2

Ejemplo: C´lculo de m´ltiplos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 187
a
u

Interacci´n entre hebras Java. Objetos compartidos . . . . . . . . . . . . . . . . . . . . . . . . . . . . 186
o

8.5.1

Implementando exclusi´n mutua en Java. C´digo y m´todos sincronizados. . . . . . . . . 186
o
o
e

Compilando y ejecutando programas Java . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 189

9 Pr´ctica 2. Programaci´n de monitores con hebras Java.
a
o
9.1
9.2
9.3

9.4
9.5
9.6

191

Objetivos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 191
Implementaci´n de monitores nativos de Java . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 191
o

9.2.1
9.2.2

Monitores como Clases en Java . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 191
M´todos de espera y notificaci´n. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 192
e
o

Implementaci´n en Java de monitores estilo Hoare . . . . . . . . . . . . . . . . . . . . . . . . . . . . 195
o

Productor-Consumidor con buffer limitado . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 198

El problema de los fumadores . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 199
El problema del barbero durmiente. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 200

10 Seminario 3. Introducci´n al paso de mensajes con MPI.
o

203

10.1 Message Passing Interface (MPI) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 204
10.2 Compilaci´n y ejecuci´n de programas MPI . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 205
o
o

10.3 Funciones MPI b´sicas . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 205
a

10.3.1 Introducci´n a los comunicadores . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 206
o
10.3.2 Funciones b´sicas de env´ y recepci´n de mensajes . . . . . . . . . . . . . . . . . . . . . . 208
a
ıo
o

10.4 Paso de mensajes s´
ıncrono en MPI . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 209
10.5 Comunicaci´n no bloqueante . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 210
o

11 Pr´ctica 3. Implementaci´n de algoritmos distribuidos con MPI.
a
o

215

11.1 Objetivos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 215
11.2 Productor-Consumidor con buffer acotado en MPI . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 215
6
CONTENTS

CONTENTS

11.2.1 Aproximaci´n inicial en MPI . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 215
o
11.2.2 Soluci´n con selecci´n no determinista . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 217
o
o

11.3 Cena de los Fil´sofos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 218
o
11.3.1 Cena de los fil´sofos en MPI . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 218
o
11.3.2 Cena de los fil´sofos con camarero en MPI . . . . . . . . . . . . . . . . . . . . . . . . . . . . 221
o

7
CONTENTS

CONTENTS

8
Part I

Gu´ de la asignatura
ıa

9
Scd 13-14 todo
Chapter 1

Gu´ de la asignatura
ıa
1.1

Datos generales

Datos generales de la asignatura.

nombre
titulaci´n
o
tipo
curso y cuatrimestre
adscrita al departamento
cr´ditos totales
e
horas semanales presen.
horas sem. no presen.
m´s informaci´n
a
o

Recursos en la Web

Sistemas Concurrentes y Distribuidos
Grado en Inform´tica
a
obligatoria (materia com´n de la rama)
u
2o curso, 1er cuatrim.
Lenguajes y Sistemas Inform´ticos
a
6 ECTS
4 horas (2 teor´ + 2 pr´cticas)
ıa
a
4 horas
http://lsi.ugr.es/scd
https://tutor2.ugr.es
http://lsi.ugr.es/lsi/node/943

En la web se pueden encontrar los siguientes recursos relacionados con la asignatura:
• P´gina Web de la asignatura con documentaci´n para alumnos:
a
o

◾ http://lsi.ugr.es/scd (para bajar la doc. se requiere login/passwd, usar login: alumno, password:
pc99scd)

• Sistema web para gesti´n de grupos, notas y comunicaci´n con alumnos (sistema Tutor)
o
o
◾ p´g. principal: https://tutor2.ugr.es
a
◾ ficha asignatura: https://tutor2.ugr.es/functions/index.php/idop 950/subject 100

• Sitio web del departamento:

◾ p´g. principal: http://lsi.ugr.es
a
◾ ficha de la asignatura: http://lsi.ugr.es/lsi/node/943
◾ profesorado depto.: http://lsi.ugr.es/lsi/personal
11
SCD (13-14). Gu´ de la asignatura.
ıa
Grupos grandes (teor´
ıa)

Gr
A
B
C
D

Grupos peque˜os (pr´cticas).
n
a

1.2

Gr
A1
A2
A3
B1
B2
B3
C1
C2
C3
D1
D2

D´
ıa
Viernes
Lunes
Jueves
Mi´rcoles
e
D´
ıa
Lunes
Martes
Jueves
Martes
Mi´rcoles
e
Viernes
Lunes
Lunes
Mi´rcoles
e
Martes
Mi´rcoles
e

Objetivos y temario

Horas
09:30-11:30
11:30-13:30
15:30-17:30
17:30-19:30
Hora
11:30-13:30
11:30-13:30
11:30-13:30
09:30-11:30
09:30-11:30
09:30-11:30
18:30-20:30
18:30-20:30
17:30-19:30
15:30-17:30
15:30-17:30

Profesor
Carlos Ure˜a Almagro
n
Jose M. Mantas Ruiz
Juan A. Holgado Terriza
Pedro Villar Castro
Profesor
Carlos Ure˜a
n
Carlos Ure˜a
n
Ana M. S´nchez
a
Pedro Villar
Jos´ Miguel Mantas
e
Ana M. S´nchez
a
Pedro Villar
Sandra S. Rodr´
ıguez
Sandra S. Rodr´
ıguez
Pedro Villar
M. del Mar Abad

Objetivos.

• Comprender la importancia de la programaci´n concurrente en las aplicaciones de hoy en d´
o
ıa.

• Identificar las principales caracter´
ısticas de los distintos tipos de sistemas concurrentes que existen.

• Conocer y entender los problemas que plantea el desarrollo de programas concurrentes, y que no
aparecen en la programaci´n secuencial.
o
• Entender los conceptos de sincronizaci´n y exclusi´n mutua entre procesos.
o
o

• Identificar las propiedades de seguridad y vivacidad que un sistema concurrente debe cumplir y ser
capaz de razonar si dichas propiedades se cumplen.
• Conocer los principales modelos de programaci´n concurrente, paralela y distribuida.
o

• Adquirir experiencia y conocimiento en los mecanismos de sincronizaci´n y comunicaci´n que se utilizan
o
o
en la actualidad para desarrollar programas concurrentes tanto para sistemas de memoria compartida
como para sistemas distribuidos.

• Entender el funcionamiento de sem´foros y monitores como mecanismos de sincronizaci´n para memoria
a
o
compartida y comprender c´mo se pueden resolver problemas de programaci´n concurrente usando
o
o
monitores.

creado October 4, 2013- p´gina 12 / 222
a
SCD (13-14). Gu´ de la asignatura.
ıa

• Ser capaz de desarrollar algoritmos para sistemas basados en memoria compartida y para sistemas
distribuidos que resuelvan problemas modelo en programaci´n concurrente.
o
• Conocer y ser capaz de usar bibliotecas y plataformas estandarizadas para la implementaci´n de
o
programas concurrentes basados en memoria compartida y para sistemas distribuidos
• Conocer las t´cnicas m´s destacadas para el dise˜o de sistemas de tiempo real
e
a
n

Temario de teor´
ıa

Se divide en los siguientes cap´
ıtulos:

1. Introducci´n a la Programaci´n Concurrente.
o
o

2. Algoritmos y mecanismos de sincronizaci´n basados en memoria compartida.
o
3. Sistemas basados en paso de mensajes.

4. Introducci´n a los sistemas de tiempo real.
o

Temario de pr´cticas
a
Pr´cticas evaluables:
a

1. Resoluci´n de problemas de sincronizaci´n con sem´foros.
o
o
a
2. Programaci´n de monitores con hebras.
o

3. Programaci´n de aplicaciones distribuidas.
o

4. Programaci´n de tareas peri´dicas con prioridades.
o
o

Seminarios impartidos presencialmente en las clases de pr´cticas:
a

1. Introducci´n a la programaci´n mutihebra usando sem´foros.
o
o
a
2. Introducci´n a la programaci´n mutihebra con monitores.
o
o

3. Introducci´n al uso de una interfaz de paso de mensajes.
o

1.3

Metodolog´ docente y evaluaci´n
ıa
o

Metodolog´ docente.
ıa

Dado el car´cter b´sico de la asignatura, se pretende que el alumno adquiera los conocimientos te´ricos
a
a
o
de la materia y los sepa aplicar con soltura. Para ello, las actividades de ense˜anza-aprendizaje que se
n
realizar´n ser´n una combinaci´n de:
a
a
o
• Actividades presenciales, entre las que se incluyen:
◾ Clases magistrales

creado October 4, 2013- p´gina 13 / 222
a
SCD (13-14). Gu´ de la asignatura.
ıa

◾ Resoluci´n de ejercicios/problemas individuales y/o en grupo
o
◾ Sesiones pr´cticas en laboratorio
a
◾ Tutor´
ıas

◾ Pruebas objetivas

• Actividades no presenciales, que pueden ser:
◾ Estudio individual o en grupo

◾ Realizaci´n de ejercicios/problemas/trabajos tanto individuales como en grupo
o
◾ Confecci´n de la carpeta de aprendizaje o portafolio de pr´cticas.
o
a

Evaluaci´n
o

Un papel importante del proceso de aprendizaje, es la evaluaci´n que tiene una doble misi´n:
o
o
• Garantizar la adquisici´n de competencias
o

• Llevar a cabo una evaluaci´n formativa en la que se fomenta la continua retroalimentaci´n del alumno
o
o
que puede conocer en todo momento c´mo va en su aprendizaje. Para ello, en todo momento:
o
◾ Se resolver´n las pruebas objetivas, ejercicios, problemas, etc.
a

◾ Se mantendr´ una carpeta de aprendizaje con todo el material generado en las pr´cticas de la
a
a
asignatura. Esta carpeta muestra el proceso de aprendizaje en pr´cticas: res´menes, ejercicios y
a
u
sus soluciones, dudas y sus respuestas, reflexiones, indagaciones y b´squeda bibliogr´fica, diario
u
a
de clase, resultados de reuniones de grupo o tutor´ etc. La carpeta ser´ revisada al menos una
ıas,
a
vez en tutor´
ıas.

Calificaci´n
o

Los criterios b´sicos para obtener la calificaci´n son los siguientes:
a
o

• La m´xima nota en teor´ y pr´cticas son 5 puntos en cada una.
a
ıa
a

• Para aprobar la asignatura es necesario tener una calificaci´n num´rica superior o igual a 5 (sobre
o
e
10), sumando teor´ y pr´cticas.
ıa
a

• Adem´s del requisito anterior, se establece como requisito adicional para superar la asignatura que,
a
tanto la calificaci´n correspondiente a la parte te´rica como la correspondiente a la parte pr´ctica,
o
o
a
sean cada una mayores o iguales a 2 (sobre 5).

Evaluaci´n de teor´ y/o pr´cticas ya superadas
o
ıa
a
Existen estas opciones:

Para los alumnos que no logren aprobar la asignatura en la convocatoria ordinaria de febrero (o septiembre) del a˜o 2014
n

Si el alumno obtiene una nota igual o superior a 2,5 en teor´ o pr´cticas, se podr´ guardar dicha nota
ıa
a
a
para la convocatoria de septiembre (o diciembre) del a˜o 2014.
n

creado October 4, 2013- p´gina 14 / 222
a
SCD (13-14). Gu´ de la asignatura.
ıa

Para los alumnos que no logren aprobar la asignatura en el curso acad´mico 2013-14
e

Si el alumno obtiene una nota igual o superior a 2,5 en pr´cticas con evaluaci´n continua, se podr´ guardar
a
o
a
dicha nota para todas las convocatorias del curso 2014-15.
Modalidades de evaluaci´n
o

Los alumnos pueden seleccionar una de las siguientes dos modalidades de evaluaci´n:
o

• Evaluaci´n continuada y formativa: Basada en la asistencia regular a clases de teor´ y pr´cticas y
o
ıa
a
la realizaci´n de las actividades propuestas.
o

• Examen final: Basada en la realizaci´n de un examen escrito relativo al temario de teor´ y la defensa
o
ıa,
de las pr´cticas ante el profesor de pr´cticas asignado al alumno.
a
a

Evaluaci´n continuada y formativa
o

En esta modalidad, los alumnos tienen que asistir a clase regularmente y realizar las pruebas y ejercicios
que se plantean a lo largo del curso.
• Deben asistir a todas las pruebas objetivas de teor´ o pr´cticas.
ıa
a

• Se admite que, de forma justificada, se falte a una prueba como m´ximo.
a

• Esta modalidad ser´ el mecanismo de evaluaci´n por defecto de todos los alumnos salvo para los que
a
o
soliciten de forma justificada (y les sea concedida) la otra modalidad (evaluaci´n unica final)
o ´

Calificaci´n de teor´ en evaluaci´n continua
o
ıa
o

La calificaci´n de teor´ (5 puntos) se reparte de la siguiente forma:
o
ıa

• 4,5 puntos corresponden a 4 pruebas objetivas individuales realizadas al final de cada tema. La
distribuci´n de la puntuaci´n por temas es la dada en la siguiente tabla:
o
o
Tema
Punt. m´x.
a

1
0,7

2
1,8

3
1,6

4
0,4

Total
4,5

• 0,5 puntos correspondiente a la resoluci´n de ejercicios, problemas, y/o trabajos.
o

Calificaci´n de pr´cticas en evaluaci´n continua
o
a
o

La calificaci´n de pr´cticas (5 puntos) se obtiene de la siguiente forma:
o
a

• 4,5 puntos correspondientes a cinco pruebas objetivas (pr´cticas 1, 2, 3, 4 y 5) que se realizan durante
a
la ultima sesi´n de pr´cticas de la parte a evaluar. Esta a su vez se distribuye como indica la siguiente
´
o
a
tabla:
Tema
Punt. m´x.
a

1
1,2

2
1,5

3
1,3

4
0,5

Total
4,5

• 0,5 puntos de las soluciones de los ejercicios propuestos que sean presentadas en clase a los compa˜eros
n
o enviadas al profesor.

La carpeta de aprendizaje podr´ ser revisada al menos una vez durante el cuatrimestre en tutor´
a
ıas

creado October 4, 2013- p´gina 15 / 222
a
SCD (13-14). Gu´ de la asignatura.
ıa
Evaluaci´n por examen final
o

Para aquellos alumnos que hayan solicitado y les haya sido concedida la evaluaci´n por esta modalidad.
o
Consta de dos partes:
• Examen de teor´ tendr´ lugar en la fecha fijada por el centro
ıa:
a

• Defensa de las pr´cticas: tendr´n lugar en las fechas en las que se reserven para este fin las aulas
a
a
de pr´cticas de la ETSIIT
a

1.4

Bibliograf´
ıa

Bibliograf´ fundamental (1/2)
ıa

• G. R. Andrews. Foundations of Multithreaded, Parallel, and Distributed Programming. Addison
Wesley, 2000.
• M. Ben-Ari. Principles of Concurrent and Distributed Programming. Prentice Hall, 2nd edition. 2006.

• J. T. Palma, C. Garrido, F. S´nchez, A. Quesada. Programaci´n Concurrente. Thomson-Paraninfo.
a
o
2003.
• G. R. Andrews. Concurrent Programming: Principles and Practice. Benjamin/Cummings, 1991.

• F. Almeida, D. Gimenez, J. M. Mantas, A.M. Vidal. Introducci´n a la Programacion Paralela. Parano
info Cengage Learning, 2008.

Bibliograf´ fundamental (2/2)
ıa

• V. Kumar , A. Grama, A. Gupta, G. Karypis. Introduction to Parallel Computing. Benjamin/Cummings
Publishing Company, 2003.

• N. Santoro. Design and analysis of distributed algorithms. Wiley Series on parallel and distributed
computing. 2007.

• A. Burns, A. Wellings. Sistemas de Tiempo Real y Lenguajes de Programaci´n. (3a edici´n). Addison
o
o
Wesley, 2003.
• G.F. Coulouris, J. Dollimore, T. Kindberg Distributed Systems: Concepts and Design (5a editci´n).
o
Pearson, 2011.

Bibliograf´ complementaria.
ıa

• N. Gehani, A.D. McGettrick. Concurrent Programming. International Computer Science Series.
Addison-Wesley. 1988.
• C. Hughes, T. Hughes. Professional Multicore Programming: Design and Implementation for C++
Developers. Wrox Programmer to Programmer. 2008.

creado October 4, 2013- p´gina 16 / 222
a
SCD (13-14). Gu´ de la asignatura.
ıa

• C. Breshears. The Art of Concurrency: A Thread Monkey´ Guide to Writing Parallel Applications.
s
´
OReilly Media. 2009.

• N.A. Lynch. Distributed Algorithms. Morgan Kaufmann. 1996.

creado October 4, 2013- p´gina 17 / 222
a
SCD (13-14). Gu´ de la asignatura.
ıa

creado October 4, 2013- p´gina 18 / 222
a
Part II

Apuntes de teor´
ıa

19
Scd 13-14 todo
Chapter 2

Tema 1. Introducci´n.
o
2.1

2.1.1

Conceptos b´sicos y motivaci´n
a
o

Conceptos b´sicos relacionados con la concurrencia
a

Programa concurrente, concurrencia y programaci´n concurrente
o

• Programa secuencial: Declaraciones de datos + Conjunto de instrucciones sobre dichos datos que
se deben ejecutar en secuencia.
• Programa concurrente:
l´gicamente en paralelo.
o

Conjunto de programas secuenciales ordinarios que se pueden ejecutar

• Proceso: Ejecuci´n de un programa secuencial.
o

• Concurrencia: Describe el potencial para ejecuci´n paralela, es decir, el solapamiento real o virtual
o
de varias actividades en el tiempo.

• Programaci´n Concurrente (PC): Conjunto de notaciones y t´cnicas de programaci´n usadas para
o
e
o
expresar paralelismo potencial y resolver problemas de sincronizaci´n y comunicaci´n.
o
o
• La PC es independiente de la implementaci´n del paralelismo. Es una abstracci´n
o
o

Programaci´n paralela, programaci´n distribuida y programaci´n de tiempo real
o
o
o

• Programaci´n paralela:
o
Su principal objetivo es acelerar la resoluci´n de problemas concretos
o
mediante el aprovechamiento de la capacidad de procesamiento en paralelo del hardware disponible.

• Programaci´n distribuida: Su principal objetivo es hacer que varios componentes software localizados
o
en diferentes ordenadores trabajen juntos.

• Programaci´n de tiempo real: Se centra en la programaci´n de sistemas que est´n funcionando
o
o
a
continuamente, recibiendo entradas y enviando salidas a/desde componentes hardware (sistemas reactivos), en los que se trabaja con restricciones muy estrictas en cuanto a la respuesta temporal (sistemas
de tiempo real).
21
SCD (13-14). Tema 1. Introducci´n..
o

2.1.2

Motivaci´n de la Programaci´n concurrente
o
o

Beneficios de la Programaci´n concurrente
o

La PC resulta m´s complicada que la programaci´n secuencial.
a
o

¿ Por qu´ es necesario conocer la Programaci´n Concurrente ?
e
o
1. Mejora de la eficiencia

La PC permite aprovechar mejor los recursos hardware existentes.
• En sistemas con un solo procesador:

◾ Al tener varias tareas, cuando la tarea que tiene el control del procesador necesita realizar una
E/S cede el control a otra, evitando la espera ociosa del procesador.
◾ Tambi´n permite que varios usuarios usen el sistema de forma interactiva (actuales sistemas
e
operativos multisusuario).

• En sistemas con varios procesadores:

◾ Es posible repartir las tareas entre los procesadores, reduciendo el tiempo de ejecuci´n.
o
◾ Fundamental para acelerar complejos c´mputos num´ricos.
o
e

Beneficios de la Programaci´n concurrente (2)
o

2. Mejora de la calidad

Muchos programas se entienden mejor en t´rminos de varios procesos secuenciales ejecut´ndose concure
a
rentemente que como un unico programa secuencial.
´
Ejemplos:

• Servidor web para reserva de vuelos: Es m´s natural, considerar cada petici´n de usuario como
a
o
un proceso e implementar pol´
ıticas para evitar situaciones conflictivas (permitir superar el l´
ımite de
reservas en un vuelo).
• Simulador del comportamiento de una gasolinera: Es m´s sencillo considerar los surtidores, clientes,
a
veh´
ıculos y empleados como procesos que cambian de estado al participar en diversas actividades
comunes, que considerarlos como entidades dentro de un unico programa secuencial.
´

2.2

2.2.1

Modelo abstracto y consideraciones sobre el hardware
Consideraciones sobre el hardware

Modelos de arquitecturas para programaci´n concurrente
o

creado October 4, 2013- p´gina 22 / 222
a
SCD (13-14). Tema 1. Introducci´n..
o

Mecanismos de implementaci´n de la concurrencia
o
• Dependen fuertemente de la arquitectura.

• Consideran una m´quina virtual que representa un sistema (multiprocesador o sistema distribuido),
a
proporcionando base homog´nea para ejecuci´n de los procesos concurrentes.
e
o
• El tipo de paralelismo afecta a la eficiencia pero no a la correcci´n.
o

Concurrencia en sistemas monoprocesador

• Multiprogramaci´n: El sistema operativo gestiona c´mo m´ltiples procesos se reparten los ciclos de
o
o
u
CPU.
• Mejor aprovechamiento CPU.

• Servicio interactivo a varios usuarios.

• Permite usar soluciones de dise˜o concurrentes.
n

• Sincronizaci´n y comunicaci´n mediante variables compartidas.
o
o

creado October 4, 2013- p´gina 23 / 222
a
SCD (13-14). Tema 1. Introducci´n..
o

Concurrencia en multiprocesadores de memoria compartida

• Los procesadores pueden compartir o no f´
ısicamente la misma memoria, pero comparten un espacio de
direcciones compartido.
• La interacci´n entre los procesos se puede implementar mediante variables alojadas en direccciones
o
del espacio compartido (variables compartidas).
• Ejemplo: PCs con procesadores muticore.

Concurrencia en sistemas distribuidos

• No existe un memoria com´n: cada procesador tiene su espacio de direcciones privado.
u

• Los procesadores interaccionan transfiri´ndose datos a trav´s de una red de interconexi´n (paso de
e
e
o
mensajes).
• Programaci´n distribuida: adem´s de la concurrencia, trata con otros problemas como el tratamiento
o
a
de los fallos, transparencia, heterogeneidad, etc.
• Ejemplos: Clusters de ordenadores, internet, intranet.

creado October 4, 2013- p´gina 24 / 222
a
SCD (13-14). Tema 1. Introducci´n..
o

2.2.2

Modelo Abstracto de concurrencia

Sentencias at´micas y no at´micas
o
o
Sentencia at´mica (indivisible)
o

Una sentencia o instrucci´n de un proceso en un programa concurrente es at´mica si siempre se ejecuta de
o
o
principio a fin sin verse afectada (durante su ejecuci´n) por otras sentencias en ejecuci´n de otros procesos
o
o
del programa.
• No se ver´ afectada cuando el funcionamiento de dicha instrucci´n no dependa nunca de como se
a
o
est´n ejecutando otras instrucciones.
e

• El funcionamiento de una instrucci´n se define por su efecto en el estado de ejecuci´n del programa
o
o
justo cuando acaba.

• El estado de ejecuci´n esta formado por los valores de las variables y los registros de todos los
o
procesos.

Ejemplos de sentencias at´micas.
o

A modo de ejemplo de instrucciones at´micas, cabe citar muchas de las instrucciones m´quina del repertorio
o
a
de un procesador, por ejemplo estas tres:
• Leer una celda de memoria y cargar su valor en ese momento en un registro del procesador
• Incrementar el valor de un registro (u otras operaciones aritm´ticas entre registros).
e
• Escribir el valor de un registro en una celda de memoria.

El resultado de estas instrucciones no depende nunca de otras intrucciones que se est´n ejecutando cone
currentemente. Al finalizar, la celda de memoria o el registro tomar´ un valor concreto predecible siempre a
a
partir del estado al inicio.
• En el caso de la escritura en memoria, por ejemplo, el hardware asegura que el valor escrito(justo al
final de la ejecuci´n) es siempre el que hab´ en el registro (justo al inicio de la ejecuci´n).
o
ıa
o

Ejemplos de sentencias no at´micas.
o

La mayor´ de las sentencias en lenguajes de alto nivel son t´
ıa
ıpicamente no at´micas, por ejemplo, la sentencia
o

§
¦

x := x + 1 ; { incrementa el valor de la variable entera ’x’ (en RAM) en una unidad }

Para ejecutarla , el compilador o int´rprete podr´ usar una secuencia de tres sentencias como esta:
e
ıa
1. leer el valor de x y cargarlo en un registro r del procesador

2. incrementar en un unidad el valor almacenado en el registro r
3. escribir el valor del registro r en la variable x

El resultado (es decir, el valor que toma x justo al acabar) depende de que haya o no haya otras sentencias
ejecut´ndose a la vez y escribiendo simult´neamente sobre la variable x. Podr´ ocurrir que el valor al final
a
a
ıa
no sea igual al valor al empezar m´s uno.
a
creado October 4, 2013- p´gina 25 / 222
a

¤
¥
SCD (13-14). Tema 1. Introducci´n..
o

Interfoliaci´n de sentencias at´micas
o
o

Supongamos que definimos un programa concurrente C compuesto de dos procesos secuenciales PA y PB
que se ejecutan a la vez.

La ejecuci´n de C puede dar lugar a cualquiera de las posibles mezclas (interfoliaciones) de sentencias
o
at´micas de PA y PB .
o
Pr.
PA
PB
C
C
C
C
C

Posibles secuencias de instr. at´micas
o
A1 A2 A3 A4 A5
B1 B2 B3 B4 B5
A1 A2 A3 A4 A5 B1 B2 B3 B4 B5
B1 B2 B3 B4 B5 A1 A2 A3 A4 A5
A1 B1 A2 B2 A3 B3 A4 B4 A5 B5
B1 B2 A1 B3 B4 A2 B5 A3 A4 A5
⋯

las sentencias at´micas se ordenan en funci´n del instante en el que acaban (que es cuando tienen efecto)
o
o
Abstracci´n
o

El modelo basado en el estudio de todas las posibles secuencias de ejecuci´n entrelazadas de los procesos
o
constituye una abstracci´n sobre las circunstancias de la ejecuci´n de los programas concurrentes, ya que:
o
o
• Se consideran exclusivamente las caracter´
ısticas relevantes que determinan el resultado del c´lculo
a
• Esto permite simplificar el an´lisis o creaci´n de los programas concurrentes.
a
o

Se ignoran los detalles no relevantes para el resultado, como por ejemplo:
• las areas de memoria asignadas a los procesos
´
• los registros particulares que est´n usando
a

• el costo de los cambios de contexto entre procesos
• la pol´
ıtica del S.O. relativa a asignaci´n de CPU
o

• las diferencias entre entornos multiprocesador o monoprocesador
• ....

Independencia del entorno de ejecuci´n
o

El entrelazamiento preserva la consistencia

El resultado de una instrucci´n individual sobre un dato no depende de las circunstancias de la ejecuci´n.
o
o

Supongamos que un programa P se compone de dos instrucciones at´micas, I0 e I1 , que se ejecutan concuro
rentemente, P I0 I1 , entonces:

creado October 4, 2013- p´gina 26 / 222
a
SCD (13-14). Tema 1. Introducci´n..
o

• Si I0 e I1 no acceden a la misma celda de memoria o registro, el orden de ejecuci´n no afecta al
o
resultado final.
• Si I0 ≡ M ← 1 y I1 ≡ M ← 2, la unica suposici´n razonable es que el resultado sea consistente. Por
´
o
tanto, al final M = 1 ´ M = 2, pero nunca por ejemplo M = 3.
o

En caso contrario, ser´ imposible razonar acerca de la correcci´n de los programas concurrentes.
ıa
o
Velocidad de ejecuci´n de los procesos. Hip´tesis del progreso finito
o
o
Progreso Finito

No se puede hacer ninguna suposici´n acerca de las velocidades absolutas/relativas de ejecuci´n de los
o
o
procesos, salvo que es mayor que cero.
Un programa concurrente se entiende en base a sus componentes (procesos) y sus interacciones, sin tener
en cuenta el entorno de ejecuci´n.
o
Ejemplo: Un disco es m´s lento que una CPU pero el programa no deber´ asumir eso en el dise˜o del
a
ıa
n
programa.
Si se hicieran suposiciones temporales:

• Ser´ dif´ detectar y corregir fallos
ıa ıcil

• La correcci´n depender´ de la configuraci´n de ejecuci´n, que puede cambiar
o
ıa
o
o

Hip´tesis del progreso finito
o

Si se cumple la hip´tesis, la velocidad de ejecuci´n de cada proceso ser´ no nula, lo cual tiene estas dos
o
o
a
consecuencias:
Punto de vista global

Durante la ejecuci´n de un programa concurrente, en cualquier momento existir´ al menos 1 proceso
o
a
preparado, es decir, eventualmente se permitir´ la ejecuci´n de alg´n proceso.
a
o
u
Punto de vista local

Cuando un proceso concreto de un programa concurrente comienza la ejecuci´n de una sentencia, completar´
o
a
la ejecuci´n de la sentencia en un intervalo de tiempo finito.
o
Estados e historias de ejecuci´n de un programa concurrente
o
Estado de un programa concurrente

Valores de las variables del programa en un momento dado. Incluyen variables declaradas expl´
ıcitamente y
variables con informaci´n de estado oculta (contador del programa, registros,...).
o

Un programa concurrente comienza su ejecuci´n en un estado inicial y los procesos van modificando el
o
estado conforme se van ejecutando sus sentencias at´micas (producen transiciones entre dos estados de
o
forma indivisible).
Historia o traza de un programa concurrente

Secuencia de estados s0 → s1 → . . . → sn , producida por una secuencia concreta de interfoliaci´n.
o

creado October 4, 2013- p´gina 27 / 222
a
SCD (13-14). Tema 1. Introducci´n..
o

Notaciones para expresar ejecuci´n concurrente
o

• Propuestas Iniciales: no separan la definici´n de los procesos de su sincronizaci´n.
o
o
• Posteriores Propuestas: separan conceptos e imponen estructura.

• Declaraci´n de procesos: rutinas espec´
o
ıficas de programaci´n concurrente
o
grama concurrente m´s clara.
a

⇒ Estructura del pro-

Sistemas Est´ticos
a

• N´mero de procesos fijado en el fuente del programa.
u
• Los procesos se activan al lanzar el programa

• Ejemplo: Message Passing Interface (MPI-1).

Sistemas Din´micos
a

• N´mero variable de procesos/hebras que se pueden activar en cualquier momento de la ejecuci´n.
u
o
• Ejemplos: OpenMP, PThreads, Java Threads, MPI-2.

Grafo de Sincronizaci´n
o

• Es un Grafo Dirigido Ac´
ıclico (DAG) donde cada nodo representa una secuencia de sentencias del
programa (actividad). Dadas dos actividades, A y B, una arista conectando A en direcci´n hacia B
o
significa que B no puede comenzar su ejecuci´n hasta que A haya finalizado.
o
P0

P1

P3

P2
P5

P4
P6

P7

• Muestra las restricciones de precedencia que determinan cu´ndo una actividad puede empezar en un
a
programa.
• Tiene que ser ac´
ıclico.

creado October 4, 2013- p´gina 28 / 222
a
SCD (13-14). Tema 1. Introducci´n..
o
Definici´n est´tica de procesos
o
a

El n´mero de procesos (arbitrario) y el c´digo que ejecutan no cambian entre ejecuciones. Cada proceso se
u
o
asocia con su identificador y su c´digo mediante la palabra clave process
o
§
var ....

{ vars. compartidas }

¤

process NomUno ;
var ....
{ vars. locales }
begin
....
{ codigo }
end

process NomDos ;
var ....
{ vars. locales }
begin
....
{ codigo }
end
...
{ otros procesos }
¦

inicio

NomUno

NomDos

fin

¥

el programa acaba cuando acaban todos los procesos. Las vars. compartidas se iniciaizan antes de comenzar
ning´n proceso.
u
Definici´n est´tica de vectores de procesos
o
a

Se pueden usar definiciones est´ticas de grupos de procesos similares que solo se diferencia en el valor de
a
una constante (vectores de procesos)
§
var ....

{ vars. compartidas }

¤

process NomP[ ind : a..b ] ;
var ....
{ vars. locales }
begin
....
{ codigo }
....
{ aqui ind vale a, a + 1,...,b }
end
...
¦

{ otros procesos }

inicio
NomP[a]

....

NomP[b]

fin
¥

• En cada caso, a y b se traducen por dos constantes concretas (el valor de a ser´ t´
a ıpicamente 0 o 1).

• El n´mero total de procesos ser´ b − a + 1 (se supone que a <= b)
u
a

Creaci´n de procesos no estructurada con fork-join.
o

• fork: sentencia que especifica que la rutina nombrada puede comenzar su ejecuci´n, al mismo tiempo
o
que comienza la sentencia siguiente (bifurcaci´n).
o

• join: sentencia que espera la terminaci´n de la rutina nombrada, antes de comenzar la sentencia
o
siguiente (uni´n).
o

creado October 4, 2013- p´gina 29 / 222
a
SCD (13-14). Tema 1. Introducci´n..
o
§
procedure P1 ;
begin
A ;
fork P2 ;
B ;
join P2 ;
C ;
end
¦

¤

§
procedure P2 ;
begin
D ;
end
¦

¤

A
A

fork
B
¥

D

B

join

D
C

C

¥

• Ventajas: pr´ctica y potente, creaci´n din´mica.
a
o
a

• Inconvenientes: no estructuraci´n, dif´ comprensi´n de los programas.
o
ıcil
o

Creaci´n de procesos estructurada con cobegin-coend
o

Las sentencias en un bloque delimitado por cobegin-coend comienzan su ejecuci´n todas ellas a la vez:
o
• en el coend se espera a que se terminen todas las sentencias.
• Hace expl´
ıcito qu´ rutinas van a ejecutarse concurrentemente.
e
§
begin
A ;
cobegin
B ; C ; D ;
coend
E ;
end
¦

¤

A

cobegin
B

C

A

D

B

E

• Ventajas: impone estructura: 1 unica entrada y 1 unica salida
´
´
• Inconveniente: menor potencia expresiva que fork-join.

2.3

D

E

coend
¥

C

⇒ m´s f´cil de entender.
a a

Exclusi´n mutua y sincronizaci´n
o
o

Exclusi´n mutua y sincronizaci´n
o
o

Seg´n el modelo abstracto, los procesos concurrentes ejecutan sus instrucciones at´micas de forma que,
u
o
en principio, es completamente arbitrario el entremezclado en el tiempo de sus respectivas secuencias de
instrucciones. Sin embargo, en un conjunto de procesos que no son independientes entre s´ (es decir, son
ı
cooperativos), algunas de las posibles formas de combinar las secuencias no son v´lidas.
a
• en general, se dice que hay una condici´n de sincronizaci´n cuando esto ocurre, es decir, que hay
o
o
alguna restricci´n sobre el orden en el que se pueden mezclar las instrucciones de distintos procesos.
o

• un caso particular es la exclusi´n mutua, son secuencias finitas de instrucciones que un proceso debe
o
ejecutar de principio a fin sin mezclarse con otras (o las mismas) de otros procesos.

creado October 4, 2013- p´gina 30 / 222
a
SCD (13-14). Tema 1. Introducci´n..
o

2.3.1

Concepto de exclusi´n mutua
o

Exclusi´n mutua
o

La restricci´n se refiere a una o varias secuencias de instrucciones consecutivas que aparecen en el texto de
o
uno o varios procesos.
• Al conjunto de dichas secuencias de instrucciones se le denomina secci´n cr´
o
ıtica (SC).

• Ocurre exclusi´n mutua (EM) cuando los procesos solo funcionan correctamente si, en cada instante
o
de tiempo, hay como mucho uno de ellos ejecutando cualquier instrucci´n de la secci´n cr´
o
o
ıtica.

es decir, el solapamiento de las instrucciones debe ser tal que cada secuencia de instrucciones de la SC se
ejecuta como mucho por un proceso de principio a fin, sin que (durante ese tiempo) otros procesos ejecuten
ninguna de esas instrucciones ni otras de la misma SC.
Ejemplos de exclusi´n mutua
o

El ejemplo t´
ıpico de EM ocurre en procesos con memoria compartida que acceden para leer y modificar
variables o estructuras de datos comunes usando operaciones no at´micas (es decir, compuestas de varias
o
instrucciones m´quina o elementales que pueden solaparse con otras secuencias), aunque hay muchos otros
a
ejemplos:

• env´ de datos a dispositivos que no se pueden compartir (p.ej., el bucle que env´ una secuencia de
ıo
ıa
datos que forma un texto a una impresora o cualquier otro dispositivo de salida v´ el bus del sistema).
ıa
• recepci´n de datos desde dispositivos (p.ej., un bucle que lee una secuencia de pulsaciones de teclas
o
desde el teclado, tambi´n a trav´s del bus).
e
e

Un ejemplo sencillo de exclusi´n mutua
o

Para ilustrar el problema de la EM, veremos un ejemplo sencillo que usa una variable entera (x) en memoria
compartida y operaciones aritm´ticas elementales.
e
• La secci´n cr´
o
ıtica esta formada por todas las secuencias de instrucciones m´quina que se obtienen al
a
traducir (compilar) operaciones de escritura (o lectura y escritura) de la variable (p.ej., asignaciones
como x:=x+1 o x:=4∗z).
• Veremos que si varios procesos ejecutan las instrucciones m´quina de la secci´n cr´
a
o
ıtica de forma
simult´nea, los resultados de este tipo de asignaciones son indeterminados.
a

aqu´ el t´rmino indeterminado indica que para cada valor de x (o del resto de variables) previo a cada
ı,
e
asignaci´n, existe un conjunto de valores distintos posibles de x al finalizar la ejecuci´n de dicha asignaci´n
o
o
o
(el valor concreto que toma x depende del orden de entremezclado de las instrucciones m´quina).
a
Traducci´n y ejecuci´n de asignaciones
o
o

Si consideramos la instrucci´n x:=x+1 (que forma la SC), veremos que una traducci´n t´
o
o ıpica a c´digo
o
m´quina tendr´ estas tres instrucciones:
a
ıa
creado October 4, 2013- p´gina 31 / 222
a
SCD (13-14). Tema 1. Introducci´n..
o
1.

load ri ← x

3.

store ri → x

2.

add ri , 1

cargar el valor de la variable x en un registro r de la CPU (por el
proceso n´mero i).
u
incrementar en una unidad el valor del registro r

guardar el valor del registro r en la posici´n de memoria de la vario
able x.

• hay dos procesos concurrentes (P0 y P1 ) que ejecutan la asignaci´n, y por tanto las tres instrucciones
o
m´quina se pueden entremezclar de forma arbitraria.
a

• cada proceso mantiene su propia copia del registro r (los llamaremos r0 y r1 )

• ambos comparten x, cuyos accesos v´ load y store son at´micos pues bloquean el bus del sistema.
ıa
o

Posibles secuencias de instrucciones

Suponemos que inicialmente x vale 0 y ambos procesos ejecutan la asignaci´n, puede haber varias secuencias
o
de interfoliaci´n, aqu´ vemos dos:
o
ı
P0
load r0 ← x
add r0 , 1
store r0 → x

P1

load r1 ← x
add r1 , 1
store r1 → x

x
0
0
1
1
1
2

P0
load r0 ← x
add r0 , 1

store r0 → x

P1

load r1 ← x
add r1 , 1

store r1 → x

x
0
0
0
0
1
1

por tanto, partiendo de x== 0, tenemos al final que la variable puede tomar el valor 1 o 2 dependiendo del
orden de ejecuci´n de las instrucciones.
o

2.3.2

Condici´n de sincronizaci´n
o
o

Condici´n de sincronizaci´n.
o
o

En general, en un programa concurrente compuesto de varios procesos, una condici´n de sincronizaci´n
o
o
establece que:
no son correctas todas las posibles interfoliaciones de las secuencias de instrucciones at´micas
o
de los procesos.

• esto ocurre t´
ıpicamente cuando, en un punto concreto de su ejecuci´n, uno o varios procesos deben
o
esperar a que se cumpla una determinada condici´n global (depende de varios procesos).
o

Veremos un ejemplo sencillo de condici´n de sincronizaci´n en el caso en que los procesos puedan usar
o
o
variables comunes para comunicarse (memoria compartida). En este caso, los accesos a las variables no
pueden ordenarse arbitrariamente (p.ej.: leer de ella antes de que sea escrita)

creado October 4, 2013- p´gina 32 / 222
a
SCD (13-14). Tema 1. Introducci´n..
o

Ejemplo de sincronizaci´n. Productor Consumidor
o

Un ejemplo t´
ıpico es el de dos procesos cooperantes en los cuales uno de ellos (productor) produce una
secuencia de valores (p.ej. enteros) y el otro (consumidor) usa cada uno de esos valores. La comunicaci´n
o
se hace v´ la variable compartida x.:
ıa

§
{ variables compartidas }
var x : integer ; { contiene cada valor producido }
¦
§
{ Proceso productor: calcula ’ x ’ }
process Productor ;
var a : integer ; { no compartida }
begin
while true do begin
{ calcular un valor }
a := ProducirValor() ;
{ escribir en mem. compartida }
x := a ; { sentencia E }
end
end
¦

¤
§
{ Proceso Consumidor: lee ’ x ’ }
process Consumidor ;
var b : integer ; { no compartida }
begin
while true do begin
{ leer de mem. compartida }
b := x ; { sentencia L }
{ utilizar el valor leido }
UsarValor(b) ;
end
end
¥
¦

Secuencias correctas e incorrectas

Los procesos descritos solo funcionan como se espera si el orden en el que se entremezclan las sentencias
elementales etiquetadas como E (escritura) y L (lectura) es: E, L, E, L, E, L, . . ..

• L, E, L, E, . . . es incorrecta: se hace una lectura de x previa a cualquier escritura (se lee valor indeterminado).

• E, L, E, E, L, . . . es incorrecta: hay dos escrituras sin ninguna lectura entre ellas (se produce un valor
que no se lee).
• E, L, L, E, L, . . . es incorrecta: hay dos lecturas de un mismo valor, que por tanto es usado dos veces.

La secuencia v´lida asegura la condici´n de sincronizaci´n:
a
o
o

• Consumidor no lee hasta que Productor escriba un nuevo valor en x (cada valor producido es usado
una sola vez).

• Productor no escribe un nuevo valor hasta que Consumidor lea el ultimo valor almacenado en x (ning´n
´
u
valor producido se pierde).

2.4

2.4.1

Propiedades de los sistemas concurrentes
Correcci´n de un sistema concurrente
o

Concepto de correcci´n de un programa concurrente
o

Propiedad de un programa concurrente: Atributo del programa que es cierto para todas las posibles
secuencias de interfoliaci´n (historias del programa).
o
creado October 4, 2013- p´gina 33 / 222
a

¤
¥
¤

¥
SCD (13-14). Tema 1. Introducci´n..
o
Hay 2 tipos:

• Propiedad de seguridad (safety).

• Propiedad de vivacidad (liveness).

2.4.2

Propiedades de seguridad y vivacidad

Propiedades de Seguridad (Safety)

• Son condiciones que deben cumplirse siempre del tipo: Nunca pasar´ nada malo.
a
• Requeridas en especificaciones est´ticas del programa.
a

• Similar a correcci´n parcial en programas secuenciales: “Si el programa termina, las respuestas deben
o
ser correctas.
• Son f´ciles de demostrar y para cumplirlas se suelen restringir las posibles interfoliaciones.
a

Ejemplos:

• Exclusi´n mutua: 2 procesos nunca entrelazan ciertas subsecuencias de operaciones.
o

• Ausencia Interbloqueo (Deadlock-freedom): Nunca ocurrir´ que los procesos se encuentren esperando
a
algo que nunca suceder´.
a

• Propiedad de seguridad en el Productor-Consumidor El consumidor debe consumir todos los datos
producidos por el productor en el orden en que se van produciendo.

Propiedades de Vivacidad (Liveness)

• Deben cumplirse eventualmente.

• Son propiedades din´micas dif´
a
ıciles de probar: Realmente sucede algo bueno

Ejemplos:

• Ausencia de inanici´n (starvation-freedom): Un proceso o grupo de procesos no puede ser indefinidao
mente pospuesto. En alg´n momento, podr´ avanzar.
u
a

• Equidad (fairness): Tipo particular de prop. de vivacidad. Un proceso que desee progresar debe
hacerlo con justicia relativa con respecto a los dem´s. M´s ligado a la implementaci´n y a veces
a
a
o
incumplida: existen distintos grados.

creado October 4, 2013- p´gina 34 / 222
a
SCD (13-14). Tema 1. Introducci´n..
o

2.5

2.5.1

Verificaci´n de programas concurrentes
o

Verificaci´n de programas concurrentes. Introducci´n
o
o

Verificaci´n de programas concurrentes. Introducci´n
o
o

¿ C´mo demostrar que un programa cumple una determinada propiedad ?
o

• Posibilidad: realizar diferentes ejecuciones del programa y comprobar que se verifica la propiedad.

• Problema: S´lo permite considerar un n´mero limitado de historias de ejecuci´n y no demuestra que
o
u
o
no existan casos indeseables.
• Ejemplo: Comprobar que el proceso P produce al final x = 3:
§
process P ;
var x : integer := 0 ;
cobegin
x := x+1 ; x := x+2 ;
coend
¦

¤

¥

Hay varias historias que llevan a x==1 o x==2 (la asignaci´n no es at´mica), pero estas historias
o
o
podr´ no aparecer dentro de un n´mero limitado de ejecuciones.
ıan
u

Verificaci´n de programas concurrentes. Enfoque operacional
o

• Enfoque operacional: An´lisis exhaustivo de casos. Se chequea la correcci´n de todas las posibles
a
o
historias.
• Problema: Su utilidad est´ muy limitada cuando se aplica a programas concurrentes complejos ya que
a
el n´mero de interfoliaciones crece exponencialmente con el n´mero de instrucciones de los procesos.
u
u

• Para el sencillo programa P (2 procesos, 3 sentencias at´micas por proceso) habr´ que estudiar 20
o
ıa
historias disferentes.

2.5.2

Enfoque axiom´tico para la verificaci´n
a
o

Verificaci´n. Enfoque axiom´tico
o
a

• Se define un sistema l´gico formal que permite establecer propiedades de programas en base a axiomas
o
y reglas de inferencia.

• Se usan f´rmulas l´gicas (asertos) para caracterizar un conjunto de estados.
o
o

• Las sentencias at´micas act´an como transformadores de predicados (asertos). Los teoremas en la
o
u
l´gica tienen la forma:
o
creado October 4, 2013- p´gina 35 / 222
a
SCD (13-14). Tema 1. Introducci´n..
o
{P}

S

{Q}

“Si la ejecuci´n de la sentencia S empieza en alg´n estado que hace verdadero el predicado P (preo
u
condici´n), entonces el predicado Q (poscondici´n) ser´ verdadero en el estado resultante.
o
o
a

• Menor Complejidad: El trabajo que conlleva la prueba de correcci´n es proporcional al n´mero de
o
u
sentencias at´micas en el programa.
o

Invariante global

• Invariante global: Predicado que referencia variables globales siendo cierto en el estado inicial de
cada proceso y manteni´ndose cierto ante cualquier asignaci´n dentro de los procesos.
e
o
• En una soluci´n correcta del Productor-Consumidor, un invariante global ser´
o
ıa:
consumidos ≤ producidos ≤ consumidos + 1

Bibliograf´ del tema 1.
ıa

Para m´s informaci´n, ejercicios, bibliograf´ adicional, se puede consultar:
a
o
ıa
1.1. Conceptos b´sicos y Motivaci´n Palma (2003), cap´
a
o
ıtulo 1.

1.2. Modelo abstracto y Consideraciones sobre el hardware Ben-Ari (2006), cap´
ıtulo 2. Andrews (2000)
cap´
ıtulo 1. Palma (2003) cap´
ıtulo 1.
1.3. Exclusi´n mutua y sincronizaci´n Palma (2003), cap´
o
o
ıtulo 1.

1.4. Propiedades de los Sistemas Concurrentes Palma (2003), cap´
ıtulo 1.

1.5. Verificaci´n de Programas concurrentes Andrews (2000), cap´
o
ıtulo 2.

2.6

1

Problemas del tema 1.

Considerar el siguiente fragmento de programa para 2 procesos P1 y P2 :

Los dos procesos pueden ejecutarse a cualquier velocidad. ¿ Cu´les son los posibles valores resultantes para
a
x ?. Suponer que x debe ser cargada en un registro para incrementarse y que cada proceso usa un registro
diferente para realizar el incremento.

creado October 4, 2013- p´gina 36 / 222
a
SCD (13-14). Tema 1. Introducci´n..
o

§
{ variables compartidas }
var x : integer := 0 ;
¦
§
process P1 ;
var i : integer ;
begin
for i := 1 to 2 do begin
x := x+1 ;
end
end
¦

¤
¤
§
process P2 ;
var j : integer ;
begin
for j := 1 to 2 do begin
x := x+1 ;
end
end
¥
¦

¥
¤

¥

2

¿ C´mo se podr´ hacer la copia del fichero f en otro g, de forma concurrente, utilizando la instrucci´n
o
ıa
o
concurrente cobegin-coend ? . Para ello, suponer que:

• los archivos son secuencia de items de un tipo arbitrario T, y se encuentran ya abiertos para lectura
(f) y escritura (g). Para leer un ´
ıtem de f se usa la llamada a funci´n leer(f) y para saber si se han
o
le´ todos los ´
ıdo
ıtems de f, se puede usar la llamada fin(f) que devuelve verdadero si ha habido al
menos un intento de leer cuando ya no quedan datos. Para escribir un dato x en g se puede usar la
llamada a procedimiento escribir(g,x).
• El orden de los ´
ıtems escritos en g debe coincidir con el de f.

• Dos accesos a dos archivos distintos pueden solaparse en el tiempo.

3

Construir, utilizando las instrucciones concurrentes cobegin-coend y fork-join, programas concurrentes
que se correspondan con los grafos de precedencia que se muestran a continuaci´n:
o

creado October 4, 2013- p´gina 37 / 222
a
SCD (13-14). Tema 1. Introducci´n..
o

4

Dados los siguientes fragmentos de programas concurrentes, obtener sus grafos de precedencia asociados:
§
begin
P0 ;
cobegin
P1 ;
P2 ;
cobegin
P3 ; P4 ; P5 ; P6 ;
coend
P7 ;
coend
P8;
end
¦

¤
§
begin
P0 ;
cobegin
begin
cobegin
P1;P2;
coend
P5;
end
begin
cobegin
P3;P4;
¥
coend
P6;
end
coend
P7 ;
end
¦

¤

¥

5

Suponer un sistema de tiempo real que dispone de un captador de impulsos conectado a un contador de
energ´ el´ctrica. La funci´n del sistema consiste en contar el n´mero de impulsos producidos en 1 hora
ıa e
o
u
(cada Kwh consumido se cuenta como un impulso) e imprimir este n´mero en un dispositivo de salida. Para
u
ello se ha de escribir un programa concurrente con 2 procesos: un proceso acumulador (lleva la cuenta de
los impulsos recibidos) y un proceso escritor (escribe en la impresora). En la variable com´n a los 2 procesos
u
n se lleva la cuenta de los impulsos. Suponiendo que el sistema se encuentra en un estado correspondiente
al valor de la variable n = N y en estas condiciones se presentan simult´neamente un nuevo impulso y el
a
final del periodo de 1 hora, obtener las posibles secuencias de ejecuci´n de los procesos y cu´les de ellas
o
a
son correctas.
Suponer que el proceso acumulador puede invocar un procedimiento Espera_impulso para esperar a que
llegue un impulso, y que el proceso escritor puede llamar a Espera_fin_hora para esperar a que termine
una hora.

En el enunciado se usan sentencias de acceso a la variable n encerradas entre los s´
ımbolos < y >. Esto
significa que cada una de esas sentencias se ejecuta en exclusi´n mutua entre los dos procesos, es decir,
o
esas sentencias se ejecutan de principio a fin sin entremezclarse entre ellas.

creado October 4, 2013- p´gina 38 / 222
a
SCD (13-14). Tema 1. Introducci´n..
o

6

Supongamos que tenemos un vector a en memoria compartida (de tama˜o par, es decir de tama˜o 2n para
n
n
alg´n n > 1), y queremos obtener en otro vector b una copia ordenada de a. Podemos usar una llamada a
u
procedimiento de la forma sort(s,t) para ordenar un segmento de a (el que va desde s hasta t, ambos
incluidos) de dos formas: (a) para ordenar todo el vector de forma secuencial con sort(1,2n);b:=a o bien
(b) para ordenar las dos mitades de a de forma concurrente, y despu´s mezclar dichas dos mitades en un
e
segundo vector b (para mezclar usamos un procedimiento merge). A continuaci´n se encuentra una posible
o
versi´n del c´digo:
o
o
§
¤
var a,b : array[1..2*n] of integer ; { n es una constante predefinida }
var uc : array[1..2] of integer ;
{ ultimo completado de cada mitad }
¦
¥
§
¤
§
¤
procedure Secuencial() ;
{ ordena el segmento de a entre s y t }
var i : integer ;
begin
procedure Sort( mitad, s, t : integer )
Sort(1,1,2n) ; {ord. a}
var i, j : integer ;
for i := 1 to 2*n do {copia a en b}
begin
b[i] := a[i] ;
for i := s to t do begin
end
for j:= s+1 to t do
procedure Concurrente() ;
if a[i] <= a[j] then
begin
swap( a[i], b[j] ) ;
cobegin
uc[mitad] := i ;
Sort(1,1,n-1);
end
Sort(2,n,2*n);
end
¦
¥
coend
Merge(1,n+1,2*n);
end
¦
¥

El c´digo de Merge se encarga de ir leyendo las dos mitades y en cada paso seleccionar el menor elemento
o
de los dos siguientes por leer en a (uno en cada mitad), y escribir dicho menor elemento en el vector mezclado
b. El c´digo es el siguiente:
o

creado October 4, 2013- p´gina 39 / 222
a
SCD (13-14). Tema 1. Introducci´n..
o

§
procedure Merge( inferior, medio, superior: integer ) ;
var k, c1, c2, ind1, ind2 : integer;
begin
{ k es la siguiente posicion a escribir en b }
k:=1 ;
{ c1 y c2 indican siguientes elementos a mezclar en cada mitad }
c1 := inferior ;
c2 := medio ;
{ mientras no haya terminado con la primera mitad }
while c1 < medio do
begin
if a[c1] < a[c2] then begin { minimo en la primera mitad }
b[k] := a[c1] ;
k
:= k+1 ;
c1
:= c1+1 ;
if c1 >= medio then { Si fin prim. mitad, copia la segunda }
for ind2 := c2 to superior do begin
b[k] := a[ind2] ;
k
:= k+1 ;
end
end
else begin { minimo en la segunda mitad }
b[k] := a[c2] ;
k
:= k+1 ;
c2
:= c2+1 ;
if c2 >= superior then begin { Si fin segunda mitad, copia primera }
for ind1 := c1 to medio do begin
b[k] := a[ind2] ;
k:=k+1;
end
c1 := medio ; { fuerza terminacion del while }
end
end
end
end
¦

¤

¥

Llamaremos Ts (k) al tiempo que tarda el procedimiento Sort cuando actua sobre un segmento del vector
con k entradas. Suponemos que el tiempo que (en media) tarda cada iteraci´n del bucle interno que hay en
o
Sort es la unidad (por definici´n). Es evidente que ese bucle tiene k(k − 1)/2 iteraciones, luego:
o
Ts (k) =

k(k − 1)
2

=

1 2 1
k − k
2
2

El tiempo que tarda la versi´n secuencial sobre 2n elementos (llamaremos S a dicho tiempo) ser´ evidenteo
a
mente Ts (2n), luego
1
1
S = Ts (2n) =
(2n)2 − (2n) = 2n2 − n
2
2
con estas definiciones, calcula el tiempo que tardar´ la versi´n paralela, en dos casos:
a
o

(1) Las dos instancias concurrentes de Sort se ejecutan en el mismo procesador (llamamos P1 al tiempo
que tarda).
creado October 4, 2013- p´gina 40 / 222
a
SCD (13-14). Tema 1. Introducci´n..
o

(2) Cada instancia de Sort se ejecuta en un procesador distinto (lo llamamos P2 )

escribe una comparaci´n cualitativa de los tres tiempos (S,P1 y P2 ).
o

Para esto, hay que suponer que cuando el procedimiento Merge actua sobre un vector con p entradas, tarda
p unidades de tiempo en ello, lo cual es razonable teniendo en cuenta que en esas circunstancias Merge
copia p valores desde a hacia b. Si llamamos a este tiempo Tm (p), podemos escribir
Tm (p) = p

.

7

Supongamos que tenemos un programa con tres matrices (a,b y c) de valores flotantes declaradas como
variables globales. La multiplicaci´n secuencial de a y b (almacenando el resultado en c) se puede hacer
o
mediante un procedimiento MultiplicacionSec declarado como aparece aqu´
ı:
§
var a, b, c : array[1..3,1..3] of real ;

procedure MultiplicacionSec()
var i,j,k : integer ;
begin
for i := 1 to 3 do
for j := 1 to 3 do begin
c[i,j] := 0 ;
for k := 1 to 3 do
c[i,j] := c[i,j] + a[i,k]*b[k,j] ;
end
end
¦

¤

¥

Escribir un programa con el mismo fin, pero que use 3 procesos concurrentes. Suponer que los elementos de
las matrices a y b se pueden leer simult´neamente, as´ como que elementos distintos de c pueden escribirse
a
ı
simult´neamente.
a

8

Un trozo de programa ejecuta nueve rutinas o actividades (P1 , P2 , . . . , P9 ), repetidas veces, de forma concurrentemente con cobegin coend (ver la figura de la izquierda), pero que requieren sincronizarse seg´n
u
determinado grafo (ver la figura de la derecha):

creado October 4, 2013- p´gina 41 / 222
a
SCD (13-14). Tema 2. Sincronizaci´n en memoria compartida..
o
Trozo de programa:

§
while true do
cobegin
P1 ; P2 ; P3 ;
P4 ; P5 ; P6 ;
P7 ; P8 ; P9 ;
coend
¦

Grafo de sincronizaci´n:
o

¤

P11
P

P33
P

P44
P

¥

P22
P
P55
P

P66
P

P77
P

P88
P

P99
P

Sup´n que queremos realizar la sincronizaci´n indicada en el grafo, usando para ello llamadas desde cada
o
o
rutina a dos procedimientos (EsperarPor y Acabar). Se dan los siguientes hechos:

• El procedimiento EsperarPor(i) es llamado por una rutina cualquiera (la n´mero k) para esperar a
u
que termine la rutina n´mero i, usando espera ocupada. Por tanto, se usa por la rutina k al inicio
u
para esperar la terminaci´n de las otras rutinas que corresponda seg´n el grafo.
o
u
• El procedimiento Acabar(i) es llamado por la rutina n´mero i, al final de la misma, para indicar que
u
dicha rutina ya ha finalizado.
• Ambos procedimientos pueden acceder a variables globales en memoria compartida.

• Las rutinas se sincronizan unica y exclusivamente mediante llamadas a estos procedimientos, siendo
´
la implementaci´n de los mismos completamente transparente para las rutinas.
o

Escribe una implementaci´n de EsperarPor y Acabar (junto con la declaraci´n e inicializaci´n de las
o
o
o
variables compartidas necesarias) que cumpla con los requisitos dados.

creado October 4, 2013- p´gina 42 / 222
a
Chapter 3

Tema 2. Sincronizaci´n en memoria
o
compartida.
3.1

Introducci´n a la sincronizaci´n en memoria compartida.
o
o

Sincronizaci´n en memoria compartida
o

En esta tema estudiaremos soluciones para exclusi´n mutua y sincronizaci´n basadas en el uso de memoria
o
o
compartida entre los procesos involucrados. Este tipo de soluciones se pueden dividir en dos categor´
ıas:

• Soluciones de bajo nivel con espera ocupada est´n basadas en programas que contienen expl´
a
ıcitamente
instrucciones de bajo nivel para lectura y escritura directamente a la memoria compartida, y bucles
para realizar las esperas.

• Soluciones de alto nivel partiendo de las anteriores, se dise˜a una capa software por encima que
n
ofrece un interfaz para las aplicaciones. La sincronizaci´n se consigue bloqueando un proceso cuando
o
deba esperar.

Soluciones de bajo nivel con espera ocupada

Cuando un proceso debe esperar a que ocurra un evento o sea cierta determinada condici´n, entra en un
o
bucle indefinido en el cual continuamente comprueba si la situaci´n ya se da o no (a esto se le llama espera
o
ocupada). Este tipo de soluciones se pueden dividir en dos categor´
ıas:

• Soluciones software: se usan operaciones est´ndar sencillas de lectura y escritura de datos simples
a
(t´
ıpicamente valores l´gicos o enteros) en la memoria compartida
o

• Soluciones hardware (cerrojos): basadas en la existencia de instrucciones m´quina espec´
a
ıficas dentro
del repertorio de instrucciones de los procesadores involucrados

Soluciones de alto nivel

Las soluciones de bajo nivel con espera ocupada se prestan a errores, producen algoritmos complicados y
tienen un impacto negativo en la eficiencia de uso de la CPU (por los bucles). En las soluciones de alto
nivel se ofrecen interfaces de acceso a estructuras de datos y adem´s se usa bloqueo de procesos en lugar
a
de espera ocupada. Veremos algunas de estas soluciones:
43
SCD (13-14). Tema 2. Sincronizaci´n en memoria compartida..
o

• Sem´foros: se construyen directamente sobre las soluciones de bajo nivel, usando adem´s servicios
a
a
del SO que dan la capacidad de bloquear y reactivar procesos.

• Regiones cr´
ıticas condicionales: son soluciones de m´s alto nivel que los sem´foros, y que se pueden
a
a
implementar sobre ellos.
• Monitores: son soluciones de m´s alto nivel que las anteriores y se pueden implementar en algunos
a
lenguajes orientados a objetos como Java o Python.

3.1.1

Estructura de los procesos con Secciones Cr´
ıticas

Entrada y salida en secciones cr´
ıticas

Para analizar las soluciones a EM asumimos que un proceso que incluya un bloque considerado como secci´n
o
cr´
ıtica (SC) tendr´ dicho bloque estructurado en tres etapas:
a

1. protocolo de entrada (PE): una serie de instrucciones que incluyen posiblemente espera, en los casos
en los que no se pueda conceder acceso a la secci´n cr´
o
ıtica.
2. secci´n cr´
o
ıtica (SC): instrucciones que solo pueden ser ejecutadas por un proceso como mucho.

3. protocolo de salida (PS): instrucciones que permiten que otros procesos puedan conocer que este
proceso ha terminado la secci´n cr´
o
ıtica.

Todas las sentencias que no forman parte de ninguna de estas tres etapas se denominan resto de sentencias
(RS) .
Acceso repetitivo a las secciones cr´
ıticas

En general, un proceso puede contener m´s de una secci´n cr´
a
o
ıtica, y cada secci´n cr´
o
ıtica puede estar
desglosada en varios bloques de c´digo separados en el texto del proceso. Para simplificar el an´lisis,
o
a
suponemos, sin p´rdida de generalidad, que:
e
• Cada proceso tiene una unica secci´n cr´
´
o
ıtica.

• Dicha secci´n cr´
o
ıtica est´ formada por un unico bloque contiguo de instrucciones.
a
´
• El proceso es un bucle infinito que ejecuta en cada iteracci´n dos pasos:
o
◾ Secci´n cr´
o
ıtica (con el PE antes y el PS despu´s)
e

◾ Resto de sentencias: se emplea un tiempo arbitrario no acotado, e incluso el proceso puede
finalizar en esta secci´n, de forma prevista o imprevista.
o

de esta forma se prevee el caso m´s general en el cual no se supone nada acerca de cuantas veces un
a
proceso puede intentar entrar en una SC.

creado October 4, 2013- p´gina 44 / 222
a
SCD (13-14). Tema 2. Sincronizaci´n en memoria compartida..
o
Condiciones sobre el comportamiento de los procesos.

Para que se puedan implementar soluciones correctas al problema de EM, es necesario suponer que:

Los procesos siempre terminan una secci´n cr´
o
ıtica y emplean un intervalo de tiempo finito desde
que la comienzan hasta que la terminan.

es decir, durante el tiempo en que un proceso se encuentra en una secci´n cr´
o
ıtica nunca
• Finaliza o aborta.

• Es finalizado o abortado externamente.
• Entra en un bucle infinito.

• Es bloqueado o suspendido indefinidamente de forma externa.

en general, es deseable que el tiempo empleado en las secciones cr´
ıticas sea el menor posible, y que las
instrucciones ejecutadas no puedan fallar.

3.1.2

Propiedades para exclusi´n mutua
o

Propiedades requeridas para las soluciones a EM

Para que un algoritmo para EM sea correcto, se deben cumplir cada una de estas tres propiedades m´
ınimas:
1. Exclusi´n mutua
o
2. Progreso

3. Espera limitada

adem´s, hay propiedades deseables adicionales que tambi´n deben cumplirse:
a
e
4. Eficiencia
5. Equidad

si bien consideramos correcto un algoritmo que no sea muy eficiente o para el que no pueda demostrarse
claramente la equidad.
Exclusi´n mutua
o

Es la propiedad fundamental para el problema de la secci´n cr´
o
ıtica. Establece que

En cada instante de tiempo, y para cada secci´n cr´
o
ıtica existente, habr´ como mucho un proceso
a
ejecutando alguna sentencia de dicha regi´n cr´
o
ıtica.

En esta secci´n veremos soluciones de memoria compartida que permiten un unico proceso en una secci´n
o
´
o
cr´
ıtica.
Si bien esta es la propiedad fundamental, no puede conseguirse de cualquier forma, y para ello se establecen
las otras dos condiciones m´
ınimas que vemos a continuaci´n.
o

creado October 4, 2013- p´gina 45 / 222
a
SCD (13-14). Tema 2. Sincronizaci´n en memoria compartida..
o
Progreso

Consideremos una secci´n cr´
o
ıtica en un instante en el cual no hay ning´n proceso ejecut´ndola, pero s´ hay
u
a
ı
uno o varios procesos en el PE compitiendo por entrar a la SC. La propiedad de progreso establece que
Un algoritmo de EM debe estar dise˜ado de forma tal que
n

1. Despu´s de un intervalo de tiempo finito desde que ingres´ el primer proceso al PE, uno
e
o
de los procesos en el mismo podr´ acceder a la SC.
a

2. La selecci´n del proceso anterior es completamente independiente del comportamiento de
o
los procesos que durante todo ese intervalo no han estado en SC ni han intentado acceder.

Cuando la condici´n (1) no se da, se dice que ocurre un interbloqueo, ya que todos los procesos en el PE
o
quedan en espera ocupada indefinidamente sin que ninguno pueda avanzar.
Espera limitada

Supongamos que un proceso emplea un intervalo de tiempo en el PE intentando acceder a una SC. Durante
ese intervalo de tiempo, cualquier otro proceso activo puede entrar un n´mero arbitrario de veces n a ese
u
mismo PE y lograr acceso a la SC (incluyendo la posibilidad de que n = 0). La propiedad establece que:
Un algoritmo de exclusi´n mutua debe estar dise˜ado de forma que n nunca ser´ superior a un
o
n
a
valor m´ximo determinado.
a

esto implica que las esperas en el PE siempre ser´n finitas (suponiendo que los procesos emplean un tiempo
a
finito en la SC).
Propiedades deseables: eficiencia y equidad.
Las propiedades deseables son estas dos:

• Eficiencia Los protocolos de entrada y salida deben emplear poco tiempo de procesamiento (excluyendo las esperas ocupadas del PE), y las variables compartidas deben usar poca cantidad de
memoria.

• Equidad En los casos en que haya varios procesos compitiendo por acceder a una SC (de forma
repetida en el tiempo), no deber´ existir la posibilidad de que sistem´ticamente se perjudique a
ıa
a
algunos y se beneficie a otros.

3.2

Soluciones software con espera ocupada para E.M.

Introducci´n
o

En esta secci´n veremos diversas soluciones para lograr exclusi´n mutua en una secci´n cr´
o
o
o
ıtica usando
variables compartidas entre los procesos o hebras involucrados. Estos algoritmos usan dichas variables para
hacer espera ocupada cuando sea necesario en el protocolo de entrada.
Los algoritmos que resuelven este problema no son triviales, y menos para m´s de dos procesos. En la
a
actualidad se conocen distintas soluciones con distintas propiedades.
Veremos estos algoritmos:

creado October 4, 2013- p´gina 46 / 222
a
SCD (13-14). Tema 2. Sincronizaci´n en memoria compartida..
o
• Algoritmo de Dekker (para 2 procesos)

• Algoritmo de Peterson (para 2 y para un n´mero arbitrario de procesos).
u

3.2.1

Refinamiento sucesivo de Dijkstra

Introducci´n al refinamiento sucesivo de Dijkstra
o

El Refinamiento sucesivo de Dijskstra hace referencia a una serie de algoritmos que intentan resolver el
problema de la exclusi´n mutua.
o
• Se comienza desde una versi´n muy simple, incorrecta (no cumple alguna de las propiedades), y
o
se hacen sucesivas mejoras para intentar cumplir las tres propiedades. Esto ilustra muy bien la
importancia de dichas propiedades.
• La versi´n final correcta se denomina Algoritmo de Dekker
o

• Por simplicidad, veremos algoritmos para 2 procesos unicamente.
´

• Se asume que hay dos procesos, denominados Proceso 0 y Proceso 1, cada uno de ellos ejecuta un
bucle infinito conteniendo:
1. Protocolo de entrada (PE).
2. Secci´n cr´
o
ıtica (SC).

3. Protocolo de salida (PS).

4. Otras sentencias del proceso (RS).

Versi´n 1. Pseudoc´digo.
o
o

En esta versi´n se usa una variable l´gica compartida (p01sc) que valdr´ true solo si el proceso 0 o el
o
o
a
proceso 1 est´n en SC, y valdr´ false si ninguno lo est´:
a
a
a
§
{ variables compartidas y valores iniciales }
var p01sc : boolean := false ; { indica si la SC esta ocupada }
¦
§
¤
§
process P0 ;
process P1 ;
begin
begin
while true do begin
while true do begin
while p01sc do begin end
while p01sc do begin end
p01sc := true ;
p01sc := true ;
{ seccion critica }
{ seccion critica }
p01sc := false ;
p01sc := false ;
{ resto seccion }
{ resto seccion }
end
end
end
end
¦
¥
¦

¤
¥
¤

¥

creado October 4, 2013- p´gina 47 / 222
a
SCD (13-14). Tema 2. Sincronizaci´n en memoria compartida..
o
Versi´n 1. Correcci´n.
o
o

Sin embargo, esa versi´n no es correcta. El motivo es que no cumple la propiedad de exclusi´n mutua,
o
o
pues ambos procesos pueden estar en la secci´n cr´
o
ıtica. Esto puede ocurrir si ambos leen p01sc y ambos
la ven a false. es decir, si ocurre la siguiente secuencia de eventos:
1. el proceso 0 accede al protocolo de entrada, ve p01sc con valor false,

2. el proceso 1 accede al protocolo de entrada, ve p01sc con valor false,
3. el proceso 0 pone p01sc a true y entra en la secci´n cr´
o
ıtica,
4. el proceso 1 pone p01sc a true y entra en la secci´n cr´
o
ıtica.

Versi´n 2. Pseudoc´digo.
o
o

Para solucionar el problema se usar´ una unica variable l´gica (turno0), cuyo valor servir´ para indicar cual
a
´
o
a
de los dos procesos tendr´ prioridad para entrar SC la pr´xima vez que llegen al PE. La variable valdr´
a
o
a
true si la prioridad es para el proceso 0, y false si es para el proceso 1:
§
{ variables compartidas y valores iniciales }
var turno0 : boolean := true ; { podria ser tambien ’false’ }
¦
§
¤
§
process P0 ;
process P1 ;
begin
begin
while true do begin
while true do begin
while not turno0 do begin end
while turno0 do begin end
{ seccion critica }
{ seccion critica }
turno0 := false ;
turno0 := true ;
{ resto seccion }
{ resto seccion }
end
end
end
end
¦
¥
¦

¤
¥
¤

¥

Versi´n 2. Correcci´n.
o
o

Esta segunda versi´n no es tampoco correcta, el motivo es distinto. Se dan estas circunstancias:
o

• Se cumple la propiedad de exclusi´n mutua. Esto es f´cil de verificar, ya que si un proceso est´ en
o
a
a
SC ha logrado pasar el bucle del protocolo de entrada y por tanto la variable turno0 tiene un valor
que forzosamente hace esperar al otro.

• No se cumple la propiedad de progreso en la ejecuci´n. El problema est´ en que este esquema obliga
o
a
a los procesos a acceder de forma alterna a la secci´n cr´
o
ıtica. En caso de que un proceso quiera
acceder dos veces seguidas sin que el otro intente acceder m´s, la segunda vez quedar´ esperando
a
a
indefinidamente.

Este es un buen ejemplo de la necesidad de tener en cuenta cualquier secuencia posible de mezcla de pasos
de procesamiento de los procesos a sincronizar.
creado October 4, 2013- p´gina 48 / 222
a
SCD (13-14). Tema 2. Sincronizaci´n en memoria compartida..
o
Versi´n 3. Pseudoc´digo.
o
o

Para solucionar el problema de la alternancia, ahora usamos dos variables l´gicas (p0sc, p1sc) en lugar de
o
solo una. Cada variable vale true si el correspondiente proceso est´ en la secci´n cr´
a
o
ıtica:
§
{ variables compartidas y valores iniciales }
var p0sc : boolean := false ; { verdadero solo si proc. 0 en SC }
p1sc : boolean := false ; { verdadero solo si proc. 1 en SC }
¦
§
¤
§
process P0 ;
process P1 ;
begin
begin
while true do begin
while true do begin
while p1sc do begin end
while p0sc do begin end
p0sc := true ;
p1sc := true ;
{ seccion critica }
{ seccion critica }
p0sc := false ;
p1sc := false ;
{ resto seccion }
{ resto seccion }
end
end
end
end
¦
¥
¦

¤

¥
¤

¥

Versi´n 3. Correcci´n.
o
o

De nuevo, esta versi´n no es correcta:
o

• Ahora s´ se cumple la propiedad de progreso en ejecuci´n, ya que los procesos no tienen que entrar
ı
o
de forma necesariamente alterna, al usar dos variables independientes. Si un proceso quiere entrar,
podr´ hacerlo si el otro no est´ en SC.
a
a

• No se cumple, sin embargo, la exclusi´n mutua, por motivos parecidos a la primera versi´n, ya que se
o
o
pueden producir secuencias de acciones como esta:
◾ el proceso 0 accede al protocolo de entrada, ve p1sc con valor falso,

◾ el proceso 1 accede al protocolo de entrada, ve p0sc con valor falso,
◾ el proceso 0 pone p0sc a verdadero y entra en la secci´n cr´
o
ıtica,
◾ el proceso 1 pone p1sc a verdadero y entra en la secci´n cr´
o
ıtica.

Versi´n 4. Pseudoc´digo.
o
o

Para solucionar el problema anterior se puede cambiar el orden de las dos sentencias del PE. Ahora las
variables l´gicas p0sc y p1sc est´n a true cuando el correspondiente proceso est´ en SC, pero tambi´n
o
a
a
e
cuando est´ intentando entrar (en el PE):
a

creado October 4, 2013- p´gina 49 / 222
a
SCD (13-14). Tema 2. Sincronizaci´n en memoria compartida..
o

§
{ variables compartidas y valores iniciales }
var p0sc : boolean := falso ; { verdadero solo si proc. 0 en PE o SC }
p1sc : boolean := falso ; { verdadero solo si proc. 1 en PE o SC }
¦
§
¤
§
process P0 ;
process P1 ;
begin
begin
while true do begin
while true do begin
p0sc := true ;
p1sc := true ;
while p1sc do begin end
while p0sc do begin end
{ seccion critica }
{ seccion critica }
p0sc := false ;
p1sc := false ;
{ resto seccion }
{ resto seccion }
end
end
end
end
¦
¥
¦

¤

¥
¤

¥

Versi´n 4. Correcci´n.
o
o

De nuevo, esta versi´n no es correcta:
o

• Ahora s´ se cumple la exclusi´n mutua. Es f´cil ver que si un proceso est´ en SC, el otro no puede
ı
o
a
a
estarlo.
• Tambi´n se permite el entrelazamiento con regiones no cr´
e
ıticas, ya que si un proceso accede al PE
cuando el otro no est´ en el PE ni en el SC, el primero lograr´ entrar a la SC.
a
a

• Sin embargo, no se cumple el progreso en la ejecuci´n, ya que puede ocurrir interbloqueo. En este
o
caso en concreto, eso puede ocurrir si se produce una secuencia de acciones como esta:
◾ el proceso 0 accede al protocolo de entrada, pone p0sc a verdadero,

◾ el proceso 1 accede al protocolo de entrada, pone p1sc a verdadero,
◾ el proceso 0 ve p1sc a verdadero, y entra en el bucle de espera,

◾ el proceso 1 ve p0sc a verdadero, y entra en el bucle de espera.

Versi´n 5. Pseudoc´digo.
o
o

Para solucionarlo, si un proceso ve que el otro quiere entrar, el primero pone su variable temporalmente a
false:

creado October 4, 2013- p´gina 50 / 222
a
SCD (13-14). Tema 2. Sincronizaci´n en memoria compartida..
o

1
2
3
4
5
6
7
8
9

10
11
12
13
14

§
var p0sc : boolean := false ; { true solo si proc. 0 en PE o SC }
p1sc : boolean := false ; { true solo si proc. 1 en PE o SC }
¦
§
¤
§
process P0 ;
process P1 ;
begin
begin
while true do begin
while true do begin
p0sc := true ;
p1sc := true ;
while p1sc do begin
while p0sc do begin
p0sc := false ;
p1sc := false ;
{ espera durante un tiempo }
{ espera durante un tiempo }
p0sc := true ;
p1sc := true ;
end
end
{ seccion critica }
{ seccion critica }
p0sc := false ;
p1sc := false ;
{ resto seccion }
{ resto seccion }
end
end
end
end
¦
¥
¦

¤
¥
¤
1
2
3
4
5
6
7
8
9

10
11
12
13
14

¥

Versi´n 5. Correcci´n.
o
o

En este caso, se cumple exclusi´n mutua pero, sin embargo, no es posible afirmar que es imposible que se
o
produzca interbloqueo en el PE. Por tanto, no se cumple la propiedad de progreso.

• La posibilidad de interbloqueo es peque˜a, y depende de c´mo se seleccionen las duraciones de los
n
o
tiempos de la espera de cortes´ de c´mo se implemente dicha espera, y de la metodolog´ usada para
ıa,
o
ıa
asignar la CPU a los procesos o hebras a lo largo del tiempo.

• En particular, y a modo de ejemplo, el interbloqueo podr´ ocurrir si ocurre que:
ıa

◾ Ambos procesos comparten una CPU y la espera de cortes´ se implementa como una espera
ıa
ocupada.
◾ Los dos procesos acceden al bucle de las l´
ıneas 4-8 (ambas variables est´n a verdadero).
a

3.2.2

◾ Sistem´ticamente, cuando un proceso est´ en la CPU y ha terminado de ejecutar la asignaci´n
a
a
o
de la l´
ınea 7, la CPU se le asigna al otro.

Algoritmo de Dekker

Algoritmo de Dekker. Descripci´n.
o

El algoritmo de Dekker debe su nombre a su inventor, es un algoritmo correcto (es decir, cumple las
propiedades m´
ınimas establecidas), y se puede interpretar como el resultado final del refinamiento sucesivo de Dijkstra:

• Al igual que en la versi´n 5, cada proceso incorpora una espera de cortes´ durante la cual le cede al
o
ıa
otro la posibilidad de entrar en SC, cuando ambos coinciden en el PE.
• Para evitar interbloqueos, la espera de cortes´ solo la realiza uno de los dos procesos, de forma
ıa
alterna, mediante una variable de turno (parecido a la versi´n 2).
o

creado October 4, 2013- p´gina 51 / 222
a
SCD (13-14). Tema 2. Sincronizaci´n en memoria compartida..
o

• La variable de turno permite tambi´n saber cuando acabar la espera de cortes´ que se implementa
e
ıa,
mediante un bucle (espera ocupada).

Algoritmo de Dekker. Pseudoc´digo.
o

1
2
3
4
5
6
7
8
9

10
11
12
13
14
15
16
17
18

§
{ variables compartidas y valores iniciales }
var p0sc
: boolean := falso ; { true solo si proc.0 en PE o SC }
p1sc
: boolean := falso ; { true solo si proc.1 en PE o SC }
turno0 : boolean := true ; { true ==> pr.0 no hace espera de cortesia }
¦
§
¤
§
process P0 ;
process P1 ;
begin
begin
while true do begin
while true do begin
p0sc := true ;
p1sc := true ;
while p1sc do begin
while p0sc do begin
if not turno0 then begin
if turno0 then begin
p0sc := false ;
p1sc := false ;
while not turno0 do
while turno0 do
begin end
begin end
p0sc := true ;
p1sc := true ;
end
end
end
end
{ seccion critica }
{ seccion critica }
turno0 := false ;
turno0 := true ;
p0sc := false ;
p1sc := false ;
{ resto seccion }
{ resto seccion }
end
end
end
end
¦
¥
¦

3.2.3

¤

¥
¤
1
2
3
4
5
6
7
8
9

10
11
12
13
14
15
16
17
18

¥

Algoritmo de Peterson

Algoritmo de Peterson. Descripci´n.
o

Este algoritmo (que tambi´n debe su nombre a su inventor), es otro algoritmo correcto para EM, que adem´s
e
a
es m´s simple que el algoritmo de Dekker.
a

• Al igual que el algoritmo de Dekker, usa dos variables l´gicas que expresan la presencia de cada
o
proceso en el PE o la SC, m´s una variable de turno que permite romper el interbloqueo en caso de
a
acceso simult´neo al PE.
a

• La asignaci´n a la variable de turno se hace al inicio del PE en lugar de en el PS, con lo cual, en
o
caso de acceso simult´neo al PE, el segundo proceso en ejecutar la asignaci´n (at´mica) al turno da
a
o
o
preferencia al otro (el primero en llegar).

• A diferencia del algoritmo de Dekker, el PE no usa dos bucles anidados, sino que unifica ambos en
uno solo.

Pseudoc´digo para 2 procesos.
o

El esquema del algoritmo queda como sigue:

creado October 4, 2013- p´gina 52 / 222
a
SCD (13-14). Tema 2. Sincronizaci´n en memoria compartida..
o

1
2
3
4
5
6
7
8
9

10
11
12

§
{ variables compartidas y valores iniciales }
var p0sc
: boolean := falso ; { true solo si proc.0 en PE o SC }
p1sc
: boolean := falso ; { true solo si proc.1 en PE o SC }
turno0 : boolean := true ; { true ==> pr.0 no hace espera de cortesia }
¦
§
¤
§
process P0 ;
process P1 ;
begin
begin
while true do begin
while true do begin
p0sc := true ;
p1sc := true ;
turno0 := false ;
turno0 := true ;
while p1sc and not turno0 do
while p0sc and turno0 do
begin end
begin end
{ seccion critica }
{ seccion critica }
p0sc := false ;
p1sc := false ;
{ resto seccion }
{ resto seccion }
end
end
end
end
¦
¥
¦

¤

¥
¤
1
2
3
4
5
6
7
8
9

10
11
12

¥

Demostraci´n de exclusi´n mutua. (1/2)
o
o

Supongamos que en un instante de tiempo t ambos procesos est´n en SC, entonces:
a

(a) La ultima asignaci´n (at´mica) a la variable turno0 (l´
´
o
o
ınea 5), previa a t, finaliz´ en un instante s (se
o
cumple s < t).

(b) En el intervalo de tiempo (s, t], ninguna variable compartida ha podido cambiar de valor, ya que en ese
intervalo ambos procesos est´n en espera ocupada o en la secci´n cr´
a
o
ıtica y no escriben esas variables.

(c) Durante el intervalo (s, t], las variables p0sc y p1sc valen verdadero, ya que cada proceso puso la
suya a verdadero antes de s, sin poder cambiarla durante (s, t].

Demostraci´n de exclusi´n mutua. (2/2)
o
o

de las premisas anteriores de deduce que:

(d) Si el proceso 0 ejecut´ el ultimo la l´
o
´
ınea 5 en el instante s, entonces no habr´ podido entrar en
ıa
SC entre s y t (la condici´n de espera del proc.0 se cumplir´ en el intervalo (s, t]), y por tanto en
o
ıa
s forzosamente fue el proceso 1 el ultimo que asign´ valor a turno0, luego turno0 vale verdadero
´
o
durante el intervalo (s, t].

(e) la condici´n anterior implica que el proceso 1 no estaba en SC en s, ni ha podido entrar a SC durante
o
(s, t] (ya que p0sc y turno0 vale verdadero), luego el proceso 1 no est´ en SC en t.
a

Vemos que se ha llegado a una contradicci´n con la hip´tesis de partida, que por tanto debe ser falsa, luego
o
o
no puede existir ning´n instante en el cual los dos procesos est´n en SC, es decir, se cumple la exclusi´n
u
e
o
m´tua.
u
Espera limitada

Supongamos que hay un proceso (p.ej. el 0) en espera ocupada en el PE, en un instante t, y veamos cuantas
veces m puede entrar a SC el proceso 1 antes de que el 0 logre hacerlo:

creado October 4, 2013- p´gina 53 / 222
a
SCD (13-14). Tema 2. Sincronizaci´n en memoria compartida..
o

• El proceso 0 puede pasar a la SC antes que el 1, en ese caso m = 0.

• El proceso 1 puede pasar a la SC antes que el 0 (que contin´a en el bucle). En ese caso m = 1.
u

En cualquiera de los dos casos, el proceso 1 no puede despu´s llegar (o volver) a SC while el 0 contin´a en
e
u
el bucle, ya que para eso el proceso 1 deber´ pasar antes por la asignaci´n de verdadero a turno0, y eso
ıa
o
provocar´ que (despu´s de un tiempo finito) forzosamente el proceso 0 entra en SC while el 1 continua en
ıa
e
su bucle.
Por tanto, la cota que requiere la propiedad es n = 1.

Progreso en la ejecuci´n
o

Para asegurar el progreso es necesario asegurar

• Ausencia de interbloqueos en el PE: Esto es f´cil de demostrar pues si suponemos que hay interbloqueo
a
de los dos procesos, eso significa que son indefinida y simult´neamente verdaderas las dos condiciones
a
de los bucles de espera, y eso implica que es verdad turno0 y no turno0, lo cual es absurdo.

• Independencia de procesos en RS: Si un proceso (p.ej. el 0) est´ en PE y el otro (el 1) est´ en
a
a
RS, entonces p1sc vale falso y el proceso 0 puede progresar a la SC independientemente del comportamiento del proceso 1 (que podr´ terminar o bloquearse estando en RS, sin impedir por ello el
ıa
progreso del proc.0). El mismo razonamiento puede hacerse al rev´s.
e

Luego es evidente que el algoritmo cumple la condici´n de progreso.
o

3.2.4

Algoritmo de Peterson para n procesos.

Algoritmo de Peterson para n procesos.

Peterson introdujo, junto con la versi´n vista, una generalizaci´n de su algoritmo para EM con n procesos.
o
o

• Cada proceso i (con 0 ≤ i < n) puede estar en uno de n + 1 estados posibles, numerados de −1 a n − 1:
◾ El estado −1 indica que el proceso est´ en RS.
a

◾ Los estados 0 al n − 2 indican que el proceso est´ en PE.
a
◾ El estado n − 1 indica que el proceso est´ en SC.
a

• Al ingresar en PE, el proceso pasa al estado 0. Durante el PE cada proceso pasa por todos los estados
0 ≤ j < n en orden, y en cada estado j (con j < n − 1) hace espera ocupada antes de pasar al j + 1.

• Las esperas est´n dise˜adas de forma que en cada estado j con j = 0, . . . , n − 1, puede haber n − j
a
n
procesos como mucho. Esto asegura la EM pues en el estado n − 1 (es decir, en SC) solo habr´ un
a
proceso como mucho.

Diagrama de estados.

Las transiciones en rojo suponen espera ocupada.
creado October 4, 2013- p´gina 54 / 222
a
SCD (13-14). Tema 2. Sincronizaci´n en memoria compartida..
o

Protocolo de entrada
Max. n

Max. n-1

Max. n-2

Max. 3

Max. 2

0
0

1
1

2
2

n-3
n-3

n-2
n-2

Max. 1

-1
-1
Resto Sección

n-1
n-1
Sección Crítica

Variables compartidas

Las variables compartidas son dos vectores de enteros (de nombres estado y ultimo), que son escritos por
cada proceso justo cuando accede a un nuevo estado:

estado: la entrada i (con 0 ≤ i < n) contiene el estado del i-´simo proceso, es un valor entero entre −1 y
e
n − 1, ambos incluidos. Debe estar inicializado a −1.

ultimo: la entrada j (con 0 ≤ j < n) contiene el ´
ındice del ultimo proceso en ingresar en el estado j (es un
´
valor entero entre 0 y n − 1). Su valor inicial es indiferente (ya que los procesos siempre escriben en
una entrada antes de leerla).
Condici´n de espera en cada estado
o

Inicialmente, todos los procesos ingresan al estado 0 al inicio del PE. El proceso i puede pasar del estado
j al estado j + 1 tras hacer una espera ocupada, hasta que se d´ una cualquiera de estas dos condiciones:
e
(a) No hay otros procesos en el estado j ni en estados posteriores a j (incluyendo SC). En este caso el
proceso i es el m´s avanzado de todos los procesos en PE o SC (decimos que i es el proceso l´
a
ıder).
Esto equivale a:
∀ k ∈ {0, . . . , n − 1} t.q. k ≠ i : estado[k] < estado[i]

(b) Despu´s de que el proceso i ingresase al estado j, otros procesos tambi´n lo han hecho. Esto equivale
e
e
a:
i ≠ ultimo[j]

creado October 4, 2013- p´gina 55 / 222
a
SCD (13-14). Tema 2. Sincronizaci´n en memoria compartida..
o
Pseudoc´digo.
o

§
{ Variables compartidas, valores iniciales y funciones }
var estado : array [0..n − 1] of integer ; { estado de cada proc. (inic. −1) }
ultimo : array [0..n − 2] of integer ; { ultimo proc. en cada estado del PE }
function lider( i : integer) : boolean; { ⇐⇒ ∀ k ≠ i : estado[k] < estado[i] }

¤

{ Procesos }
process P[ mi_numero : 0 .. n − 1 ] ;
begin
while true do begin
for mi_etapa := 0 to n − 2 do begin
estado[mi_numero] := mi_etapa ;
ultimo[mi_etapa] := mi_numero ;
while ultimo[mi_etapa]==mi_numero and not lider(mi_numero) do
begin end
end
estado[mi_numero] := n − 1 ;
{ seccion critica }
estado[mi_numero] := −1 ;
{ resto seccion }
end
¦

¥

La funci´n l´gica lider.
o o

La funci´n lider lee la variable compartida estado, y devuelve verdadero solo si el i-´simo proceso es el m´s
o
e
a
avanzado de todos los que est´n en PE y SC:
a
§
function lider( i : integer ) : boolean ;
begin
for k := 0 to n − 1 do
if i ≠ k and estado[i] ≤ estado[k] then
return false ;
return true ;
end
¦

3.3

3.3.1

¤

¥

Soluciones hardware con espera ocupada (cerrojos) para E.M.
Introducci´n
o

Introducci´n
o

Los cerrojos constituyen una soluci´n hardware basada en espera ocupada que puede usarse en procesos
o
concurrentes con memoria compartida para solucionar el problema de la exclusi´n mutua.
o

• La espera ocupada constituye un bucle que se ejecuta hasta que ning´n otro proceso est´ ejecutando
u
e
instrucciones de la secci´n cr´
o
ıtica

• Existe un valor l´gico en una posici´n de memoria compartida (llamado cerrojo) que indica si alg´n
o
o
u
proceso est´ en la secci´n cr´
a
o
ıtica o no.

creado October 4, 2013- p´gina 56 / 222
a
SCD (13-14). Tema 2. Sincronizaci´n en memoria compartida..
o

• En el protocolo de salida se actualiza el cerrojo de forma que se refleje que la SC ha quedado libre

Veremos una soluci´n elemental que sin embargo es incorrecta e ilustra la necesidad de instrucciones
o
hardware espec´
ıficas (u otras soluciones m´s elaboradas).
a
Una posible soluci´n elemental
o

Vemos un esquema para procesos que ejecutan SC y RS repetidamente:

§
{ variables compartidas y valores iniciales }
var sc_ocupada : boolean := false ; { cerrojo: verdadero solo si SC ocupada }
{ procesos }
process P[ i : 1 .. n ];
begin
while true do begin
while sc_ocupada do begin end
sc_ocupada := true ;
{ seccion critica }
sc_ocupada := false ;
{ resto seccion }
end
end
¦

¤

¥

Errores de la soluci´n simple
o

La soluci´n anterior no es correcta, ya que no garantiza exclusi´n mutua al existir secuencias de mezclado
o
o
de instrucciones que permiten a m´s de un proceso ejecutar la SC a la vez:
a
• La situaci´n se da si n procesos acceden al protocolo de entrada y todos ellos leen el valor del cerrojo
o
a false (ninguno lo escribe antes de que otro lo lea).
• Todos los procesos registran que la SC est´ libre, y todos acceden a ella.
a

• El problema es parecido al que ya vimos de acceso simult´neo a una variable en memoria compartida:
a
la lectura y posterior escritura del cerrojo se hace en varias sentencias distintas que se entremezclan.

una soluci´n es usar instrucciones m´quina at´micas (indivisibles) para acceso a la zona de memoria donde
o
a
o
se aloja el cerrojo. Veremos dos de ellas: LeerAsignar (TestAndSet) e Intercambia (Swap).

3.3.2

La instrucci´n LeerAsignar.
o

La instrucci´n LeerAsignar.
o

Es una instrucci´n m´quina disponible en el repertorio de algunos procesadores.
o
a

• admite como argumento la direcci´n de memoria de la variable l´gica que actua como cerrojo.
o
o
• se invoca como una funci´n desde LLPP de alto nivel, y ejecuta estas acciones:
o
1. lee el valor anterior del cerrojo

creado October 4, 2013- p´gina 57 / 222
a
SCD (13-14). Tema 2. Sincronizaci´n en memoria compartida..
o
2. pone el cerrojo a verdadero

3. devuelve el valor anterior del cerrojo

• al ser una unica instrucci´n m´quina su ejecuci´n no puede entremezclarse con ninguna otra instrucci´n
´
o a
o
o
ejecutada en el mismo procesador

• bloquea el bus del sistema y la memoria donde est´ el cerrojo de forma que ninguna otra instrucci´n
a
o
similar de otro procesador puede entremezclarse con ella.

Protocolos de entrada y salida con LeerAsignar

La forma adecuada de usar LeerAsignar es la que se indica en este esquema:

§
{ variables compartidas y valores iniciales }
var sc_ocupada : boolean := false ; { true solo si la SC esta ocupada }
{ procesos }
process P[ i : 1 .. n ];
begin
while true do begin
while LeerAsignar( sc_ocupada ) do begin end
{ seccion critica }
sc_ocupada := false ;
{ resto seccion }
end
end
¦

¤

¥

cuando hay m´s de un proceso intentando entrar en SC (estando SC libre), solo uno de ellos (el primero en
a
ejecutar LeerAsignar) ve el cerrojo (sc ocupada) a falso, lo pone a verdadero y logra entrar a SC.

3.3.3

La instrucci´n Intercambia.
o

La instrucci´n Intercambia.
o

Constituye otra instrucci´n hardware que, al igual que LeerAsignar, se ejecuta de forma at´mica en entornos
o
o
con varios procesos ejecut´ndose en uno o varios procesadores compartiendo memoria.
a
• actua sobre un cerrojo (un valor l´gico) en memoria compartida
o
• admite dos argumentos:

◾ la direcci´n de memoria del cerrojo (variable global en memoria compartida)
o

◾ la direcci´n de memoria de otra variable l´gica (no necesariamente compartida, t´
o
o
ıpicamente es
una variable local del proceso que llama a Intercambia)

o
o
• el efecto de la instrucci´n es intercambiar los dos valores l´gicos almacenados en las posiciones de
memoria indicadas

• se invoca como un procedimiento

creado October 4, 2013- p´gina 58 / 222
a
SCD (13-14). Tema 2. Sincronizaci´n en memoria compartida..
o
Protocolos de entrada y salida con Intercambia

La forma de usar Intercambia es como se indica aqu´
ı:

§
{ variables compartidas y valores iniciales }
var sc_libre : boolean := true ; { verdadero solo si la SC esta libre }
{ procesos }
process P[ i : 1 .. n ];
var { variable no compartida: true solo si este proceso ocupa la SC }
sc_ocupada_proc : boolean := falso ;
begin
while true do begin
repeat
Intercambia( sc_libre, sc_ocupada_proc ) ;
until sc_ocupada_proc ;
{ seccion critica }
intercambia( sc_libre, sc_ocupada_proc ) ;
{ resto seccion }
end
end
¦

¤

¥

Validez de Intercambia para exclusi´n mutua
o
Se puede verificar que funciona:

• si hay n procesos conteniendo una secci´n cr´
o
ıtica, habr´ n + 1 variables l´gicas involucradas:
a
o
◾ n variables locales (sc ocupada proc), una por proceso

◾ el cerrojo (sc libre)

• en cada instante de tiempo, exactamente una de esas n + 1 variables l´gicas vale verdadero, y el resto
o
valen falso

• este invariante se cumple debido a que:

◾ es inicialmente cierto (ver los valores iniciales)
◾ las llamadas a Intercambia no lo hacen falso

por tanto se cumple la exclusi´n mutua ya que en cada instante solo el proceso cuya variable local este a
o
verdadero (si es que hay alguno) est´ en SC.
a

3.3.4

Desventajas de los cerrojos.

Desventajas de los cerrojos.

Los cerrojos constituyen una solucion v´lida para EM que consume poca memoria y es eficiente en tiempo
a
(excluyendo las esperas ocupadas), sin embargo:

• las esperas ocupadas consumen tiempo de CPU que podr´ dedicarse a otros procesos para hacer
ıa
trabajo util
´

creado October 4, 2013- p´gina 59 / 222
a
SCD (13-14). Tema 2. Sincronizaci´n en memoria compartida..
o

• se puede acceder directamente a los cerrojos y por tanto un programa err´neo o escrito malinteno
cionadamente puede poner un cerrojo en un estado incorrecto, pudiendo dejar a otros procesos indefinidamente en espera ocupada.
• en la forma b´sica que hemos visto no se cumplen ciertas condiciones de equidad
a

3.3.5

Uso de los cerrojos.

Uso de los cerrojos.

Las desventajas indicadas hacen que el uso de cerrojos sea restringido, en el sentido que:

• por seguridad, normalmente solo se usan desde componentes software que forman parte del sistema
operativo, librer´ de hebras, de tiempo real o similares (estas componentes suelen estar bien comıas
probadas y por tanto libres de errores o c´digo malicioso).
o
• para evitar la p´rdida de eficiencia que supone la espera ocupada, se usan solo en casos en los que
e
la ejecuci´n de la SC conlleva un intervalo de tiempo muy corto (por tanto las esperas ocupadas son
o
muy cortas, y la CPU no se desaprovecha).

3.4

3.4.1

Sem´foros para sincronizaci´n
a
o
Introducci´n
o

Sem´foros. Introducci´n
a
o

Los sem´foros constituyen un mecanismo que soluciona o aminora los problemas indicados para los cerrojos,
a
y tienen un ambito de uso m´s amplio:
´
a
• no se usa espera ocupada, sino bloqueo de procesos (uso mucho m´s eficiente de la CPU)
a
• resuelven f´cilmente el problema de exclusi´n mutua con esquemas de uso sencillos
a
o

• se pueden usar para resolver problemas de sincronizaci´n (aunque en ocasiones los esquemas de uso
o
son complejos)
• el mecanismo se implementa mediante instancias de una estructura de datos a las que se accede
unicamente mediante subprogramas espec´
´
ıficos. Esto aumenta la seguridad y simplicidad.

Bloqueo y desbloqueo de procesos

Los sem´foros exigen que los procesos que deseen acceder a una SC no ocupen la CPU mientras esperan a
a
que otro proceso o hebra abandone dicha SC, esto implica que:
• un proceso en ejecuci´n debe poder solicitar quedarse bloqueado
o

• un proceso bloqueado no puede ejecutar instrucciones en la CPU

• un proceso en ejecuci´n debe poder solicitar que se desbloquee (se reanude) alg´n otro proceso
o
u
bloqueado.

creado October 4, 2013- p´gina 60 / 222
a
SCD (13-14). Tema 2. Sincronizaci´n en memoria compartida..
o

• deben poder existir simult´neamente varios conjuntos de procesos bloqueados.
a

• cada petici´n de bloqueo o desbloqueo se debe referir a alguno de estos conjuntos.
o

Todo esto requiere el uso de servicios externos (proporcionados por el sistema operativo o por la librer´ de
ıa
hebras), mediante una interfaz bien definida.

3.4.2

Estructura de un sem´foro
a

Estructura de un sem´foro
a

Un sem´foro es un instancia de una estructura de datos (un registro) que contiene los siguientes elementos:
a
• Un conjunto de procesos bloqueados (de estos procesos decimos que est´n esperando al sem´foro).
a
a

• Un valor natural (un valor entero no negativo), al que llamaremos por simplicidad valor del sem´foro
a

Estas estructuras de datos residen en memoria compartida. Al inicio de un programa que los usa debe poder
inicializarse cada sem´foro:
a
• el conjunto de procesos asociados estar´ vac´
a
ıo
• se deber´ indicar un valor inicial del sem´foro
a
a

3.4.3

Operaciones sobre los sem´foros.
a

Operaciones sobre los sem´foros
a

Adem´s de la inicializaci´n, solo hay dos operaciones b´sicas que se pueden realizar sobre una variable u
a
o
a
objeto cualquiera de tipo sem´foro (que llamamos s) :
a
• sem wait(s)

◾ Si el valor de s es mayor que cero, decrementar en una unidad dicho valor

◾ Si el valor de s es cero, bloquear el proceso que invoca en el conjunto de procesos bloqueados
asociado a s

• sem signal(s)

◾ Si el conjunto de procesos bloqueados asociado a s no est´ vac´ desbloquear uno de dichos
a
ıo,
procesos.

◾ Si el conjunto de procesos bloqueados asociado a s est´ vac´ incrementar en una unidad el valor
a
ıo,
de s.

Invariante de un sem´foro
a

Dado un sem´foro s, en un instante de tiempo cualquiera t (en el cual el valor de s no est´ en proceso de
a
e
actualizaci´n) se cumplir´ que:
o
a
v0 + n s = v t + n w
todos estos s´
ımbolos desginan n´meros enteros no negativos, en concreto:
u

creado October 4, 2013- p´gina 61 / 222
a
SCD (13-14). Tema 2. Sincronizaci´n en memoria compartida..
o
v0 = valor inicial de s

vt = valor de s en el instante t.

ns = n´mero total de llamadas a sem signal(s) completadas hasta el instante t.
u

nw = n´mero total de llamadas a sem wait(s) completadas hasta el instante t (no se incluyen los sem wait no
u
completados por haber dejado el proceso en espera).

Implementaci´n de sem wait y sem signal.
o
Se pueden implementar con este esquema:

§
procedure sem_wait(var s:semaphore);
begin
if s.valor > 0 then
s.valor := s.valor - 1 ;
else
bloquear( s.procesos ) ;
end
¦

¤
§
procedure sem_signal(var s:semaphore);
begin
if vacio( s.procesos ) then
s.valor := s.valor + 1 ;
else
desbloquear( s.procesos ) ;
end
¥
¦

¤

¥

En un sem´foro cualquiera, estas operaciones se ejecutan de forma at´mica, es decir, no puede haber dos
a
o
procesos distintos ejecutando estas operaciones a la vez sobre un mismo sem´foro (excluyendo el per´
a
ıodo de
bloqueo que potencialmente conlleva la llamada a sem wait).

3.4.4

Uso de los sem´foros
a

Uso de sem´foros para exclusi´n mutua
a
o

Los sem´foros se pueden usar para EM usando un sem´foro inicializado a 1, y haciendo sem wait en el
a
a
protocolo de entrada y sem signal en el protocolo de salida:

§
{ variables compartidas y valores iniciales }
var sc_libre : semaphore := 1 ; { vale 1 si SC esta libre, 0 si SC esta ocupada }

{ procesos }
process P[ i : 0..n ];
begin
while true do begin
sem_wait( sc_libre ) ; { esperar bloqueado hasta que sc libre sea 1 }
{ seccion critica: ...... }
sem_signal( sc_libre ) ; { desbloquear proc. en espera o poner sc libre a 1 }
{ resto seccion: ....... }
end
end
¦

En cualquier instante de tiempo, la suma del valor del sem´foro m´s el n´mero de procesos en la SC es la
a
a
u
unidad. Por tanto, solo puede haber 0 o 1 procesos en SC, y se cumple la exclusi´n mutua.
o
creado October 4, 2013- p´gina 62 / 222
a

¤

¥
SCD (13-14). Tema 2. Sincronizaci´n en memoria compartida..
o
Uso de sem´foros para sincronizaci´n
a
o

El problema del Productor-Consumidor que vimos se puede resolver f´cilmente con sem´foros:
a
a

§
{ variables compartidas y valores iniciales }
var x
: integer ;
{
producidos
: integer :=0 ;
{
consumidos
: integer :=0 ;
{
puede_leer
: semaphore := 0 ; {
puede_escribir : semaphore := 1 ; {
¦
§
process Productor ; { calcula ’x’ }
var a : integer ;
begin
while true do begin
a := ProducirValor() ;
sem_wait( puede_escribir );
x := a ; { sentencia E }
producidos := producidos+1 ;
sem_signal( puede_leer ) ;
end
end
¦

contiene cada valor producido }
numero de valores producidos }
numero de valores consumidos }
1 si se puede leer ’x’, 0 en otro caso }
1 si se puede escribir ’x’, 0 en otro caso }
¤
§
process Consumidor { lee ’x’ }
var b : integer ;
begin
while true do begin
sem_wait( puede_leer ) ;
b := x ; { sentencia L }
consumidos := consumidos+1 ;
sem_signal( puede_escribir ) ;
UsarValor(b) ;
end
end
¥
¦

Limitaciones de los sem´foros
a

Los sem´foros resuelven de una forma eficiente y sencilla el problema de la exclusi´n mutua y problemas
a
o
sencillos de sincronizaci´n, sin embargo:
o

• los problemas m´s complejos de sincronizaci´n se resuelven de forma algo m´s compleja (es dif´
a
o
a
ıcil
verificar su validez, y es f´cil que sean incorrectos).
a

• al igual que los cerrojos, programas err´neos o malintencionados pueden provocar que haya procesos
o
bloqueados indefinidamente o en estados incorrectos.

En la siguiente secci´n se ver´ una soluci´n de m´s alto nivel sin estas limitaciones (monitores).
o
a
o
a

3.5

3.5.1

Monitores como mecanismo de alto nivel
Fundamento te´rico de los monitores
o

Fundamento te´rico de los monitores
o

• Inconvenientes de usar mecanismos como los sem´foros:
a

◾ Basados en variables globales: esto impide un dise˜o modular y reduce la escalabilidad (incorn
porar m´s procesos al programa suele requerir la revisi´n del uso de las variables globales).
a
o

◾ El uso y funci´n de las variables no se hace expl´
o
ıcito en el programa, lo cual dificulta razonar
sobre la correcci´n de los programas.
o

creado October 4, 2013- p´gina 63 / 222
a

¤

¥
¤

¥
SCD (13-14). Tema 2. Sincronizaci´n en memoria compartida..
o

◾ Las operaciones se encuentran dispersas y no protegidas (posibilidad de errores).

• Es necesario un mecanismo que permita el acceso estructurado y la encapsulaci´n, y que adem´s proo
a
porcione herramientas para garantizar la exclusi´n mutua e implementar condiciones de sincronizaci´n
o
o

3.5.2

Definici´n de monitor
o

Definici´n de monitor
o

• C.A.R. Hoare (1974) Monitor: mecanismo de alto nivel que permite:
◾ Definir objetos abstractos compartidos:

▸ Colecci´n de variables encapsuladas (datos) que representan un recurso compartido por varios
o
procesos.
▸ Conjunto de procedimientos para manipular el recurso: afectan a las variables encapsuladas.

◾ Garantizar el acceso exclusivo a las variables e implementar sincronizaci´n.
o

• El recurso compartido se percibe como un objeto al que se accede concurrentemente.
• Acceso estructurado y Encapsulaci´n:
o

◾ El usuario (proceso) solo puede acceder al recurso mediante un conjunto de operaciones.

◾ El usuario ignora la/s variable/s que representan al recurso y la implementaci´n de las operao
ciones asociadas.

Propiedades de un monitor

Exclusi´n mutua en el acceso a los procedimientos
o

• La exclusi´n mutua en el acceso a los procedimientos del monitor est´ garantizada por definici´n.
o
a
o

• La implementaci´n del monitor garantiza que nunca dos procesos estar´n ejecutando simult´neamente
o
a
a
alg´n procedimiento del monitor (el mismo o distintos).
u

Ventajas sobre los sem´foros (soluci´n no estructurada)
a
o

• Las variables est´n protegidas, evitando interferencias exteriores.
a

• Acceso estructurado: Un proceso cualquiera solo puede acceder a las variables del monitor usando
los procedimientos exportados por el monitor. Toda la espera y se˜alizaci´n se programan dentro del
n
o
monitor. Si el monitor es correcto, lo ser´ cada instancia usada por los procesos.
a
• Exclusi´n mutua garantizada: evita errores.
o

creado October 4, 2013- p´gina 64 / 222
a
SCD (13-14). Tema 2. Sincronizaci´n en memoria compartida..
o
Sintaxis de un monitor

Estructura de una declaraci´n de un monitor, de nombre nombre-monitor, con N procedimientos (con nombres:
o
nom proc 1,nom proc 2,. . .,nom proc n), de los cuales algunos son exportados (nom exp 1,nom exp 2,....):

§
monitor nombre monitor ;

var
...... ;
export
nom exp 1,nom exp 2 .... ;

¤

{ declaracion de variables permanentes (privadas) }
{
(se conservan entre llamadas al monitor) }
{ declaracion de procedimientos publicos
}
{
(se indican solo los nombres) }

procedure nom proc 1( ... ); { decl. de procedimiento y sus parametros formales }
var ...
;
{ declaracion de variables locales a nom proc 1 }
begin
...
{ codigo que implementa nom proc 1 }
end
...
{ resto de procedimientos del monitor }

begin
....
end
¦

{ codigo de inicializacion de vars. permanentes }

Componentes de un monitor

1. Un conjunto de variables permanentes:

• Almacenan el estado interno del recurso compartido que est´ siendo representado por el monitor.
a

• S´lo pueden ser accedidas dentro del monitor (en el cuerpo de los procedimientos y c´digo de
o
o
inicializaci´n).
o
• Permanecen sin modificaciones entre dos llamadas consecutivas a procedimientos del monitor.

2. Un conjunto de procedimientos internos:

• Manipulan las variables permanentes.

• Pueden tener variables y par´metros locales, que toman un nuevo valor en cada activaci´n del
a
o
procedimiento.
• Algunos (o todos) constituyen la interfaz externa del monitor y podr´n ser llamados por los
a
procesos que comparten el recurso.

3. Un c´digo de inicializaci´n:
o
o

• Inicializa las variables permanentes del monitor.

• Se ejecuta una unica vez, antes de cualquier llamada a procedimiento del monitor.
´

creado October 4, 2013- p´gina 65 / 222
a

¥
SCD (13-14). Tema 2. Sincronizaci´n en memoria compartida..
o
Diagrama de las componentes del monitor

El monitor se puede visualizar como aparece en el diagrama:

• El uso que se hace del monitor se hace exclusivamente usando los procedimientos exportados (constituyen el interfaz con el exterior).

• Las variables permanentes y los procedimientos no
exportados no son accesibles desde fuera.

• Ventaja: la implementaci´n de las operaciones se
o
puede cambiar sin modificar su sem´ntica.
a

Ejemplo de monitor (pseudoc´digo)
o

Monitor M
Variables
permanentes

Procedimientos
exportados
C´digo de
o
inicializaci´n
o

OP1
OP2

···

OPn

Tenemos varios procesos que pueden incrementar (en una unidad) una variable compartida y poder examinar
su valor en cualquier momento:
§
{ declaracion del monitor }

monitor VariableCompartida ;
var x : integer; { permanente }
export incremento, valor;

¤
§
{ ejemplo de uso del monitor
}
{ (debe aparecer en el ambito de la }
{ declaracion del monitor)
}

VariableCompartida.incremento();
VariableCompartida.valor( k ) ;
¦

¤

¥

procedure incremento( );
begin
x := x+1 ; { incrementa valor actual }
end;
procedure valor(var v:integer);
begin
v := x ; { copia sobre v valor actual }
end;
begin
x := 0 ; { inicializa valor }
end
¦

¥

creado October 4, 2013- p´gina 66 / 222
a
SCD (13-14). Tema 2. Sincronizaci´n en memoria compartida..
o

3.5.3

Funcionamiento de los monitores

Funcionamiento de los monitores

• Comunicaci´n monitor-mundo exterior: Cuando un proceso necesita operar sobre un recurso comparo
tido controlado por un monitor deber´ realizar una llamada a uno de los procedimientos exportados
a
por el monitor usando los par´metros reales apropiados.
a
◾ Cuando un proceso est´ ejecutando un procedimiento exportado del monitor decimos que est´
a
a
dentro del monitor.

• Exclusi´n mutua: Si un proceso est´ ejecutando un procedimiento del monitor (est´ dentro del mismo),
o
a
a
ning´n otro proceso podr´ entrar al monitor (a cualquier procedimiento del mismo) hasta que el proceso
u
a
que est´ dentro del monitor termine la ejecuci´n del procedimiento que ha invocado.
a
o
◾ Esta pol´
ıtica de acceso asegura que las variables permanentes nunca son accedidas concurrentemente.
◾ El acceso exclusivo entre los procedimientos del monitor debe estar garantizado en la implementaci´n de los monitores
o

Funcionamiento de los monitores (2)

• Los monitores son objetos pasivos:

Despu´s de ejecutar el c´digo de inicializaci´n, un monitor es un objeto pasivo y el c´digo de sus
e
o
o
o
procedimientos s´lo se ejecuta cuando estos son invocados por los procesos.
o

• Instanciaci´n de monitores: Para cada recurso compartido se tendr´ que definir un monitor. Para
o
ıa
recursos con estructura y comportamiento id´nticos podemos instanciar (de forma parametrizada) el
e
monitor tantas veces como recursos se quieran controlar.
◾ Declaraci´n de un tipo monitor e instanciaci´n:
o
o

§
class monitor nombre clase monitor( parametros formales ) ;
.... .......... { cuerpo del monitor semejante a los anteriores }
end
var nombre instancia : nombre clase monitor( parametros actuales ) ;
¦

◾ Implementaciones reentrantes: poder crear una nueva instancia independiente de un monitor
para una tarea determinada permite escribir c´digo reentrante que realiza dicha tarea.
o

Ejemplo de instanciaci´n de un monitor
o

Podemos escribir un ejemplo similar a VariableCompartida, pero ahora parametrizado:

creado October 4, 2013- p´gina 67 / 222
a

¤

¥
SCD (13-14). Tema 2. Sincronizaci´n en memoria compartida..
o

§
{ declaracion del monitor }

class monitor VarComp(pini,pinc : integer);
var x, inc : integer;
export incremento, valor;

procedure incremento( );
begin
x := x+inc ;
end;
procedure valor(var v : integer);
begin
v := x ;
end;
begin
x:= pini ; inc := pinc ;
end
¦

¤
§
{ ejemplo de uso }

var mv1
: VarComp(0,1);
mv2
: VarComp(10,4);
i1,i2 : integer ;
begin
mv1.incremento() ;
mv1.valor(i1) ; { i1==1 }
mv2.incremento() ;
mv2.valor(i2) ; { i2==14 }
end
¦

¤

¥

¥

Cola del monitor para exclusi´n mutua
o

El control de la exclusi´n mutua se basa en la existencia de la cola del monitor:
o

• Si un proceso est´ dentro del monitor y otro proceso intenta ejecutar un procedimiento del monitor,
a
´ste ultimo proceso queda bloqueado y se inserta en la cola del monitor
e
´

• Cuando un proceso abandona el monitor (finaliza la ejecuci´n del procedimiento), se desbloquea un
o
proceso de la cola, que ya puede entrar al monitor

• Si la cola del monitor est´ vac´ el monitor est´ libre y el primer proceso que ejecute una llamada a
a
ıa,
a
uno de sus procedimientos, entrar´ en el monitor
a

• Para garantizar la vivacidad del sistema, la planificaci´n de la cola del monitor debe seguir una pol´
o
ıtica
FIFO

Cola del monitor

Esta cola forma parte del estado del monitor:

creado October 4, 2013- p´gina 68 / 222
a
SCD (13-14). Tema 2. Sincronizaci´n en memoria compartida..
o

Monitor M
Cola del
Monitor

Variables
permanentes

Procedimientos
exportados

3.5.4

C´digo de
o
inicializaci´n
o

Proceso7

OP1

···
M.OP2 ()
···
M.OP1 ()
···

Proceso4 · · ·
···
M.OP4 ()
···
M.OP1 ()
···

Proceson
···
M.OPi ()
···
M.OPj ()
···

null

OP2

···

OPn

Sincronizaci´n en monitores
o

Sincronizaci´n en monitores
o

• Para implementar la sincronizaci´n, se requiere de una facilidad para bloqueo-activaci´n de acuerdo
o
o
a una condici´n.
o
• En sem´foros, las instrucciones de sincronizaci´n presentan:
a
o
◾ Bloqueo-activaci´n
o

◾ Cuenta, para representar la condici´n.
o

• En monitores:

◾ S´lo se dispone de sentencias Bloqueo-activaci´n.
o
o

◾ La condici´n se representa mediante los valores de las variables permanentes del monitor.
o

Primitivas de bloqueo-activaci´n en monitores
o

◾ wait: Estoy esperando a que alguna condici´n ocurra.
o
Bloquea al proceso llamador.

◾ signal: Estoy se˜alando que una condici´n ocurre.
n
o
Reactiva a un proceso esperando a dicha condici´n (si no hay ninguno no hace nada).
o

creado October 4, 2013- p´gina 69 / 222
a
SCD (13-14). Tema 2. Sincronizaci´n en memoria compartida..
o
Ejemplo de monitor para planificar un ´nico recurso
u

Este monitor permite gestionar el acceso a un recurso que debe usarse en E.M. por parte de varios procesos:
§
monitor recurso;

ocupado
: boolean;
noocupado : condition;
export adquirir, liberar ;

¤

var

¦
§
procedure adquirir;
begin
if ocupado then noocupado.wait();
ocupado := true;
end;
¦
§
{ inicializacion }
begin
ocupado := false;
end
¦

¤
§
procedure liberar;
begin
ocupado:=false;
noocupado.signal();
end;
¥
¦

¥
¤

¥
¤

¥

Variables condici´n o se˜ales (1)
o
n

Para gestionar las condiciones de sincronizaci´n en monitores se utilizan las se˜ales o variables de
o
n
condici´n:
o
• Debe declararse una variable condici´n para cualquier condici´n l´gica de sincronizaci´n que se pueda
o
o o
o
dar entre los procesos del programa (por cada raz´n de bloqueo basada en los valores de las variables
o
permanentes del monitor).
• No tienen valor asociado (no requieren inicializaci´n).
o

• Representan colas (inicialmente vac´ de procesos esperando la condici´n.
ıas)
o

• M´s de un proceso podr´ estar dentro del monitor, aunque solo uno estar´ ejecut´ndose (el resto
a
a
a
a
estar´n bloqueados en variables condici´n).
a
o

Colas de condici´n o se˜ales (2)
o
n

• Dada una variable condici´n cond, se definen al menos las siguientes operaciones asociadas a cond:
o
Operaciones sobre variables condici´n
o

◾ cond.wait(): Bloquea al proceso que la llama y lo introduce en la cola de la variable condici´n.
o
◾ cond.signal(): Si hay procesos bloqueados por esa condici´n, libera uno de ellos.
o

◾ cond.queue(): Funci´n booleana que devuelve verdadero si hay alg´n proceso esperando en
o
u
la cola de cond y falso en caso contrario.

• Cuando hay m´s de un proceso esperando en una condici´n cond:
a
o

creado October 4, 2013- p´gina 70 / 222
a
SCD (13-14). Tema 2. Sincronizaci´n en memoria compartida..
o

◾ Propiedad FIFO: cond.signal() reactivar´ al proceso que lleve m´s tiempo esperando.
a
a
◾ Evita la inanici´n: Cada proceso en cola obtendr´ eventualmente su turno.
o
a

Variables condici´n y colas asociadas.
o

Los procesos 2 y 5 ejecutan las operaciones 1 y 2, ambas producen esperas de la condici´n B.
o

Monitor M
Cola del
Monitor

Proceso7

Variables
permanentes
Variables
condici´n
o

Cond.A

null

Cond.B
···

Procedimientos
exportados
C´digo de
o
inicializaci´n
o

Proceso4 · · ·

OP1
OP2

···
B.wait
···

···

OPn

Proceso2
···
B.wait
···
B.wait

···
M.OP1 ()
···

Proceson

null

Proceso5
···
M.OP2 ()
···

null

Colas de condici´n con prioridad
o

• Por defecto, se usan colas de espera FIFO.

• A veces resulta util disponer de un mayor control sobre la estrategia de planificaci´n, dando la prioridad
´
o
del proceso en espera como un nuevo par´metro:
a
cond.wait (prioridad:integer)

◾ Tras bloqueo, ordena los procesos en cola en base al valor de prioridad

◾ cond.signal() reanuda proceso que especific´ el valor m´s bajo de prioridad.
o
a

• Precauci´n al dise˜ar el monitor: Evitar riesgos como la inanici´n.
o
n
o

• Ning´n efecto sobre la l´gica del programa: Funcionamiento similar con/sin colas de prioridad.
u
o
• S´lo mejoran las caracter´
o
ısticas dependientes del tiempo.

creado October 4, 2013- p´gina 71 / 222
a
SCD (13-14). Tema 2. Sincronizaci´n en memoria compartida..
o
Ejemplo de cola con prioridad(1): Asignador

Asigna un recurso al siguiente trabajo m´s corto:
a
§
monitor asignador;

libre : boolean ;
turno : condition ;
export peticion, liberar ;

¤

var

¦
§
procedure peticion(tiempo: integer);
begin
if not libre then
turno.wait( tiempo );
libre := false ;
end
¦
§
{ inicializacion }
begin
libre := true ;
end
¦

¤
§
procedure liberar() ;
begin
libre := true ;
turno.signal();
end
¦
¥

¥
¤

¥

Ejemplo de cola con prioridad (2): Reloj con alarma

El proceso llamador se retarda n unidades de tiempo:
§
monitor despertador;

ahora
: integer ;
despertar : condition ;
export despiertame, tick ;

¥
¤

¤

var

¦
§
procedure despiertame( n: integer );
var alarma : integer;
begin
alarma := ahora + n;
while ahora<alarma do
despertar.wait( alarma );
despertar.signal();
{ por si otro proceso
coincide en la alarma }
end
¦
§
{ Inicializacion }
begin
ahora := 0 ;
end
¦

El problema de los lectores-escritores (LE)

¤
§
procedure tick();
begin
ahora := ahora+1 ;
despertar.signal();
end
¦

¥
¤

¥

¤

¥

¥

creado October 4, 2013- p´gina 72 / 222
a
SCD (13-14). Tema 2. Sincronizaci´n en memoria compartida..
o

En este ejemplo, hay dos tipos de procesos que acceden concurrentemente a una estructura de datos en
memoria compartida:

escritores son procesos que modifican la estructura de datos (escriben en ella). El c´digo de escritura no
o
puede ejecutarse concurrentemente con ninguna otra escritura ni lectura, ya que est´ formado por una
a
secuencia de instrucciones que temporalmente ponen la estructura de datos en un estado no usable
por otros procesos.
lectores son procesos que leen a estructura de datos, pero no modifican su estado en absoluto. El c´digo
o
de lectura puede (y debe) ejecutarse concurrentemente por varios lectores de forma arbitraria, pero no
puede hacerse a la vez que la escritura.
la soluci´n de este problema usando sem´foros es compleja, veremos que con monitores es sencillo.
o
a
LE: vars. permanentes y procedimientos para lectores
§
monitor Lec_Esc ;
var

n_lec
escribiendo
lectura
escritura

:
:
:
:

integer
boolean
condition
condition

;
;
;
;

{
{
{
{

¤

numero de lectores leyendo }
true si hay algun escritor escribiendo }
no hay escritores escribiendo, lectura posible }
no hay lectores ni escritores, escritura posible }

export inicio_lectura, fin_lectura,
inicio_escritura, fin_escritura ;
¦
§
¤
§
procedure inicio_lectura()
procedure fin_lectura()
begin
begin
if escribiendo then { si hay escritor }
n_lec:= n_lec - 1;
lectura.wait() ; { se bloquea }
if n_lec = 0 then
n_lec := n_lec + 1 ;
{ si es el ultimo lector , }
{ desbloqueo en cadena de posibles }
{ desbloquear a un escritor }
{ procesos lectores bloqueados
}
escritura.signal()
lectura.signal()
end
¦
end
¦
¥

¥
¤

¥

LE: procedimientos para escritores

creado October 4, 2013- p´gina 73 / 222
a
SCD (13-14). Tema 2. Sincronizaci´n en memoria compartida..
o
§
procedure inicio_escritura()
begin
{si hay procs. accediendo: esperar}
if n_lec > 0 or escribiendo then
escritura.wait()
escribiendo:= true;
end;
¦
§
begin { inicializacion }
n_lec := 0 ;
escribiendo := false ;
end
¦

¤
§
procedure fin_escritura()
begin
escribiendo:= false;
if lectura.queue() then {si hay lect.:}
lectura.signal();
{despertar uno }
else
{si no hay lect:}
escritura.signal() ;
{desp. escr.}
¥
end;
¦

¥
¤

¥

LE: uso del monitor

Los procesos lectores y escritores tendr´ el siguiente aspecto:
ıan
§
monitor Lec_Esc ;
....
end
¦
§
process Lector[ i:1..n ] ;
begin
while true do begin
..........
Lec_Esc.inicio_lectura() ;
{ codigo de lectura }
Lec_Esc.fin_lectura() ;
..........
end
end
¦

¤

¤

¤
§
process Escritor[ i:1..m ] ;
begin
while true do begin
..........
Lec_Esc.inicio_escritura() ;
{ codigo de escritura }
Lec_Esc.fin_escritura() ;
..........
end
end
¥
¦

¥
¤

¥

En esta implementaci´n se ha dado prioridad a los lectores (en el momento que un escritor termina, si hay
o
escritores y lectores esperando, pasan los lectores).

3.5.5

Sem´ntica de las se˜ales de los monitores
a
n

Efectos de las operaciones sobre la E.M.

• Es necesario liberar la E.M. del monitor justo antes de ejecutar una operaci´n cond.wait() para no
o
generar un interbloqueo en la cola de procesos del monitor.

• Cuando se libera un proceso que est´ esperando por una condici´n cond (proceso se˜alado) es porque
a
o
n
otro proceso (proceso se˜alador) ha ejecutado una operaci´n cond.signal():
n
o
◾ El proceso se˜alado tiene preferencia para acceder al monitor frente a los que esperan en la cola
n
del monitor (ya que ´stos podr´ cambiar el estado que ha permitido su liberaci´n).
e
ıan
o

creado October 4, 2013- p´gina 74 / 222
a
SCD (13-14). Tema 2. Sincronizaci´n en memoria compartida..
o

◾ Si el proceso se˜alador continuase ”dentro” del monitor, tendr´
n
ıamos una violaci´n de la E.M. del
o
monitor
◾ El comportamiento concreto del proceso se˜alador depender´ de la sem´ntica de se˜ales que se
n
a
a
n
haya establecido en la implementaci´n del monitor.
o

• Algunos lenguajes implementan una operaci´n que permite liberar a todos los procesos esperando por
o
una condici´n (signal_all).
o

Se˜alar y continuar (SC)
n

• El proceso se˜alador contin´a su ejecuci´n dentro del monitor hasta que sale del mismo (porque
n
u
o
termina la ejecuci´n del procedimiento) o se bloquea en una condici´n. En ese momento, el proceso
o
o
se˜alado se reactiva y contin´a ejecutando c´digo del monitor.
n
u
o
• Al continuar dentro del monitor, el proceso se˜alador podr´ cambiar el estado del monitor y hacer
n
ıa
falsa la condici´n l´gica por la que esperaba el proceso se˜alado.
o o
n

• Por tanto, en el proceso se˜alado no se puede garantizar que la condici´n asociada a cond es cierta
n
o
al terminar cond.wait(), y l´gicamente es necesario volver a comprobarla entonces.
o
• Esta sem´ntica obliga a programar la operaci´n wait en un bucle, de la siguiente manera:
a
o
§

¤

while not condicion l´gica desbloqueo do
o
cond.wait() ;

¦

¥

Se˜alar y salir (SS)
n

• Si hay procesos bloqueados por la condici´n cond, el proceso se˜alador sale del monitor despu´s de
o
n
e
ejecutar cond.signal().
• En ese caso, la operaci´n signal conlleva:
o
◾ Liberar al proceso se˜alado.
n

◾ Terminaci´n del procedimiento del monitor que estaba ejecutando el proceso se˜alador.
o
n

• Est´ asegurado el estado que permite al proceso se˜alado continuar la ejecuci´n del procedimiento
a
n
o
del monitor en el que se bloque´ (la condici´n de desbloqueo se cumple).
o
o

• Esta sem´ntica condiciona el estilo de programaci´n ya que obliga a colocar siempre la operaci´n
a
o
o
signal como ´ltima instrucci´n de los procedimientos de monitor que la usen.
u
o

Se˜alar y esperar (SE)
n

• El proceso se˜alador se bloquea justo despu´s de ejecutar la operaci´n signal.
n
e
o
• El proceso se˜alado entra de forma inmediata en el monitor.
n

creado October 4, 2013- p´gina 75 / 222
a
SCD (13-14). Tema 2. Sincronizaci´n en memoria compartida..
o

• Est´ asegurado el estado que permite al proceso se˜alado continuar la ejecuci´n del procedimiento
a
n
o
del monitor en el que se bloque´.
o

• El proceso se˜alador entra en la cola de procesos del monitor, por lo que est´ al mismo nivel que el
n
a
resto de procesos que compiten por la exclusi´n mutua del monitor.
o

• Puede considerarse una sem´ntica ”injusta” respecto al proceso se˜alador ya que dicho proceso ya
a
n
hab´ obtenido el acceso al monitor por lo que deber´ tener prioridad sobre el resto de procesos que
ıa
ıa
compiten por el monitor.

Se˜alar y espera urgente (SU)
n

• Esta soluci´n intenta corregir el problema de falta de equitatividad de la soluci´n anterior.
o
o
• El proceso se˜alador se bloquea justo despu´s de ejecutar la operaci´n signal.
n
e
o
• El proceso se˜alado entra de forma inmediata en el monitor.
n

• Est´ asegurado el estado que permite al proceso se˜alado continuar la ejecuci´n del procedimiento
a
n
o
del monitor en el que se bloque´.
o

• El proceso se˜alador entra en una nueva cola de procesos que esperan para acceder al monitor, que
n
podemos llamar cola de procesos urgentes.

• Los procesos de la cola de procesos urgentes tienen preferencia para acceder al monitor frente a los
procesos que esperan en la cola del monitor.
• Es la sem´ntica que se supone en los ejemplos vistos.
a

Procesos en la cola de urgentes.

El proceso 1 y el 9 han ejecutado la op.2, que hace signal de la cond. B.

creado October 4, 2013- p´gina 76 / 222
a
SCD (13-14). Tema 2. Sincronizaci´n en memoria compartida..
o

Monitor M
Cola del
Monitor

Variables
permanentes
Variables
condici´n
o

Cond.A

null

Cond.B
···

Procedimientos
exportados
C´digo de
o
inicializaci´n
o

Cola de
urgentes (SU)

Proceso4 · · ·

Proceso7

OP1
OP2

OP1
···
B.wait()
···

OP2
···
B.signal()
···

···

OPn

Proceso1
···
M.OP2 ()
···

Proceson

Proceso2
···
M.OP1 ()
···

Proceso9
···
M.OP2 ()
···

Proceso5
···
M.OP1 ()
···

null

null

null

An´lisis comparativo de las diferentes sem´nticas
a
a
Potencia expresiva

Todas las sem´nticas son capaces de resolver los mismos problemas.
a
Facilidad de uso

La sem´ntica SS condiciona el estilo de programaci´n y puede llevar a aumentar de forma ”artificial” el
a
o
n´mero de procedimientos.
u
Eficiencia

• Las sem´nticas SE y SU resultan ineficientes cuando la operaci´n signal se ejecuta al final de los
a
o
procedimientos del monitor.
El proceso se˜alador se bloquea dentro del monitor cuando ya no le quedan m´s instrucciones que
n
a
ejecutar en el procedimiento, suponiendo un bloqueo innecesario que conlleva un innecesario doble
cambio de contexto en CPU (reactivaci´n se˜alado + salida).
o
n

• La sem´ntica SC tambi´n es un poco ineficiente al obligar a usar un bucle while para cada instrucci´n
a
e
o
signal.
creado October 4, 2013- p´gina 77 / 222
a
SCD (13-14). Tema 2. Sincronizaci´n en memoria compartida..
o

3.5.6

Implementaci´n de monitores
o

Implementaci´n de monitores con sem´foros
o
a

La exclusi´n mutua en el acceso a los procs. del monitor se puede implementar con un unico sem´foro mutex
o
´
a
inicializado a 1:
§
procedure P1(...)
begin
sem_wait(mutex);
{ cuerpo del procedimiento }
sem_signal(mutex);
end
¦

¤
§
{ inicializacion }
mutex := 1 ;
¦

¤
¥

¥

Para implementar la sem´ntica SU necesitamos adem´s un sem´foro next, para implementar la cola de
a
a
a
urgentes, y una variable entera next_count para contar los procesos bloqueados en esa cola:
§
procedure P1(...)
begin
sem_wait(mutex);
{ cuerpo del procedimiento }
if next_count > 0 then sem_signal(next);
else sem_signal(mutex);
end
¦

¤
§
{ inicializacion }
next := 0 ;
next_count :=0 ;
¦

¤

¥

¥

Implementaci´n de monitores con sem´foros
o
a

Para implementar las variables condici´n le asociamos un sem´foro a cada una de ellas x_sem (inicializado
o
a
a 0) y una variable para contar los procesos bloqueados en cada una de ellas (x_sem_count inicializada a
0):

Implementaci´n de x.wait()
o
§
x_sem_count := x_sem_count + 1 ;
if next_count <> 0 then
sem_signal(next) ;
else
sem_signal(mutex);
sem_wait(x_sem);
x_sem_count := x_sem_count - 1 ;
¦

Implementaci´n de x.signal()
o
¤
§
if x_sem_count <> 0 then begin
next_count := next_count + 1 ;
sem_signal(x_sem);
sem_wait(next);
next_count := next_count - 1 ;
end
¦
¥

Implementaci´n de monitores con sem´foros
o
a

Cada monitor tiene asociadas las siguientes colas de procesos:
• Cola del monitor: controlada por el sem´foro mutex.
a

• Cola de procesos urgentes: controlada por el sem´foro next y el n´mero de procesos en cola se
a
u
contabiliza en la variable next_count. Esta cola solo es necesaria para implementar la sem´ntica
a
SU.
creado October 4, 2013- p´gina 78 / 222
a

¤

¥
SCD (13-14). Tema 2. Sincronizaci´n en memoria compartida..
o

• Colas de procesos bloqueados en cada condici´n: controladas por el sem´foro asociado a cada
o
a
condici´n (x_sem) y el n´mero de procesos en cada cola se contabiliza en una variable asociada a
o
u
cada condici´n (x_sem_count).
o

Esta implementaci´n no permite llamadas recursivas a los procedimientos del monitor y no asegura la
o
suposici´n FIFO sobre las colas de exclusi´n mutua y de las se˜ales.
o
o
n
Los sem´foros y monitores son equivalentes en potencia expresiva pero los monitores facilitan el desarrollo.
a

3.5.7

Verificaci´n de monitores
o

Verificaci´n de programas con monitores
o

• La verificaci´n de la correcci´n de un programa concurrente con monitores requiere:
o
o
◾ Probar la correcci´n de cada monitor.
o

◾ Probar la correcci´n de cada proceso de forma aislada.
o

◾ Probar la correcci´n de la ejecuci´n concurrente de los procesos implicados.
o
o

• El programador no puede conocer a priori el orden en que se ejecutar´n los procedimientos del monitor.
a
• El enfoque de verificaci´n que vamos a seguir utiliza un invariante de monitor:
o

◾ Establece una relaci´n constante entre los valores permitidos de las variables del monitor.
o
◾ Debe ser cierto cuando un procedimiento empieza a ejecutarse.

◾ Debe ser cierto cuando un procedimiento termine de ejecutarse.

◾ Debe ser cierto cuando un procedimiento llegue a una llamada a wait.

Invariante del monitor (I M)

• I M se ha de cumplir despu´s de la inicializaci´n de las variables permanentes.
e
o

• I M se ha de cumplir antes y despu´s de cada acci´n.
e
o

• I M se ha de cumplir antes y despu´s de cada operaci´n wait. Una vez el proceso ha sido liberado (por
e
o
una operaci´n signal ejecutada por otro proceso), se debe cumplir la condici´n que permite liberarlo.
o
o
• IM se ha de cumplir antes y despu´s de cada operaci´n signal sobre una condici´n. Tambi´n se debe
e
o
o
e
cumplir antes la condici´n que permite liberar a un proceso.
o

Bibliograf´ del tema 2.
ıa

Para m´s informaci´n m´s detallada, ejercicios y bibliograf´ adicional, se puede consultar:
a
o
a
ıa
2.1. Introducci´n Palma (2003) cap´
o
ıtulo 3.

2.2. Soluciones software con Espera Ocupada para E.M. Palma (2003) cap´
ıtulo 3, Ben Ari (2006) cap´
ıtulo
3
creado October 4, 2013- p´gina 79 / 222
a
SCD (13-14). Tema 2. Sincronizaci´n en memoria compartida..
o

2.3. Soluciones hardware con Espera Ocupada para E.M. Palma (2003) cap´
ıtulo 3, Andrews (2000)
cap´
ıtulo 3
2.4. Sem´foros para sincronizaci´n. Palma (2003) cap´
a
o
ıtulo 4, Andrews (2000) cap´
ıtulo 4, Ben Ari (2006)
cap´
ıtulo 6
2.5. Monitores como mecanismo de alto nivel. Palma (2003) cap´
ıtulo 6, Andrews (2000) cap´
ıtulo 5, Ben
Ari (2006) cap´
ıtulo 7

3.6

9

Problemas del tema 2.

¿Podr´ pensarse que una posible soluci´n al problema de la exclusi´n mutua, ser´ el siguiente algoritmo
ıa
o
o
ıa
que no necesita compartir una variable Turno entre los 2 procesos?
(a) ¿Se satisface la exclusi´n mutua?
o

(b) ¿Se satisface la ausencia de interbloqueo?

1
2
3
4
5
6
7
8
9

10
11
12
13
14

§
{ variables compartidas y valores iniciales }
var c0, c1 : integer ; { los valores iniciales no son relevantes }
¦
§
¤
§
Process P0 ;
process P1 ;
begin
begin
while true do begin
while true do begin
c0 := 0 ;
c1 := 0 ;
while c1 = 0 do begin
while c0 = 0 do begin
c0 := 1 ;
c1 := 1 ;
while c1 = 0 do begin end
while c0 = 0 do begin end
c0 := 0 ;
c1 := 0 ;
end
end
{ seccion critica }
{ seccion critica }
c0 := 1 ;
c1 := 1 ;
{ resto sentencias }
{ resto seccion }
end
end
end
end
¦
¥
¦

¤
¥
¤
1
2
3
4
5
6
7
8
9

10
11
12
13
14

¥

10

Al siguiente algoritmo se le conoce como soluci´n de Hyman al problema de la exclusi´n mutua. ¿Es correcta
o
o
dicha soluci´n?
o
creado October 4, 2013- p´gina 80 / 222
a
SCD (13-14). Tema 2. Sincronizaci´n en memoria compartida..
o

1
2
3
4
5
6
7
8
9

10
11
12
13

§
{ variables compartidas y valores iniciales }
var c0
: integer := 1 ;
c1
: integer := 1 ;
turno : integer := 1 ;
¦
§
process P0 ;
begin
while true do begin
c0 := 0 ;
while turno != 0 do begin
while c1 = 0 do begin end
turno := 0 ;
end
{ seccion critica }
c0 := 1 ;
{ resto sentencias }
end
end
¦

¤

¥
¤

¤
§
process P1 ;
begin
while true do begin
c1 := 0 ;
while turno != 1 do begin
while c0 = 0 do begin end
turno := 1 ;
end
{ seccion critica }
c1 := 1 ;
{ resto sentencias }
end
end
¥
¦

1
2
3
4
5
6
7
8
9

10
11
12
13

¥

11

Se tienen 2 procesos concurrentes que representan 2 m´quinas expendedoras de tickets (se˜alan el turno
a
n
en que ha de ser atendido el cliente), los n´meros de los tickets se representan por dos variables n1 y n2
u
que valen inicialmente 0. El proceso con el n´mero de ticket m´s bajo entra en su secci´n cr´
u
a
o
ıtica. En caso
de tener 2 n´meros iguales se procesa primero el proceso n´mero 1.
u
u
a) Demostrar que se verifica la ausencia de bloqueo y la ausencia de inanci´n.
o

b) Demostrar que las asignaciones n1:=1 y n2:=1 son ambas necesarias.

§
{ variables compartidas y valores iniciales }
var n1 : integer := 0 ;
n2 : integer := 0 ;
¦
§
process P1 ;
begin
while true do begin
n1 := 1 ;
{
n1 := n2+1 ;
{
while n2 != 0 and
{
n2 < n1 do begin end;{
{ seccion critica }
n1 := 0 ;
{
{ resto sentencias }
end
end
¦

1.0
1.1
1.2
1.3

}
}
}
}

1.4 }

¤
§
process P2 ;
begin
while true do begin
n2 := 1 ;
{ 2.0
n2 := n1+1 ;
{ 2.1
while n1 != 0 and
{ 2.2
n1 <= n2 do begin end;{ 2.3
{ seccion critica }
n2 := 0 ;
{ 2.4
{ resto sentencias }
end
end
¥
¦

¤

¥
¤

}
}
}
}
}

¥

creado October 4, 2013- p´gina 81 / 222
a
SCD (13-14). Tema 2. Sincronizaci´n en memoria compartida..
o

12

El siguiente programa es una soluci´n al problema de la exclusi´n mutua para 2 procesos. Discutir la
o
o
correcci´n de esta soluci´n: si es correcta, entonces probarlo. Si no fuese correcta, escribir escenarios que
o
o
demuestren que la soluci´n es incorrecta.
o

1
2
3
4
5
6
7
8
9

10
11

§
{ variables compartidas y valores iniciales }
var c0 : integer := 1 ;
c1 : integer := 1 ;
¦
§
process P0 ;
begin
while true do begin
repeat
c0 := 1-c1 ;
until c1 != 0 ;
{ seccion critica }
c0 := 1 ;
{ resto sentencias }
end
end
¦

¤

¤
§
process P1 ;
begin
while true do begin
repeat
c1 := 1-c0 ;
until c0 != 0 ;
{ seccion critica }
c1 := 1 ;
{ resto sentencias }
end
end
¥
¦

¥
¤
1
2
3
4
5
6
7
8
9

10
11

¥

13

Considerar el siguiente algoritmo de exclusi´n mutua para n procesos (algoritmo de Knuth). Escribir un
o
escenario en el que 2 procesos consiguen pasar el bucle de las l´
ıneas 14 a 16, suponiendo que el turno lo
tiene inicialmente el proceso 0.

creado October 4, 2013- p´gina 82 / 222
a
SCD (13-14). Tema 2. Sincronizaci´n en memoria compartida..
o

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24

§
{ variables compartidas y valores iniciales }
var c
: array[0..n-1] of (pasivo,solicitando,enSC) := [pasivo,..,pasivo];
turno: integer := 0 ;
¦
§
process P[ i : 0..n-1 ] ;
begin
while true do begin
repeat
c[i] := solicitando ;
j := turno;
while j <> i do begin
if c[j] <> pasivo then
j := turno ;
else
j := (j-1) mod n ;
end
c[i] := enSC ;
k := 0;
while k<=n and ( k=i or c[k]<>enSC ) do
k := k+1;
until k > n ;
turno := i ;
{ seccion critica }
turno := (i-1) mod n ;
c[i] := pasivo ;
{ resto sentencias }
end
end
¦

14

¤

¥
¤

¥

Supongamos que tres procesos concurrentes acceden a dos variables compartidas (x e y) seg´n el siguiente
u
esquema:
§
var x, y : integer ;
¦
§
{ accede a ’ x ’ }
process P1 ;
begin
while true do begin
x := x+1 ;
{ .... }
end
end
¦

¤

¤
§
{ accede a ’ x ’ e ’ y’ }
process P2 ;
begin
while true do begin
x := x+1 ;
y := x ;
{ .... }
end
¥
end
¦

¤
§
{ accede a ’ y’ }
process P3 ;
begin
while true do begin
y := y+1 ;
{ .... }
end
end
¦
¥

¥
¤

¥

con este programa como referencia, realiza estas dos actividades:

1. usando un unico sem´foro para exclusi´n mutua, completa el programa de forma que cada proceso
´
a
o

creado October 4, 2013- p´gina 83 / 222
a
SCD (13-14). Tema 2. Sincronizaci´n en memoria compartida..
o

realice todos sus accesos a x e y sin solaparse con los otros procesos (ten en cuenta que el proceso
2 debe escribir en y el mismo valor que acaba de escribir en x).

2. la asignaci´n x:=x+1 que realiza el proceso 2 puede solaparse sin problemas con la asignaci´n y:=y+1
o
o
que realiza el proceso 3, ya que son independientes. Sin embargo, en la soluci´n anterior, al usar un
o
unico sem´foro, esto no es posible. Escribe una nueva soluci´n que permita el solapamiento descrito,
´
a
o
usando dos sem´foros para dos secciones cr´
a
ıticas distintas (las cuales, en el proceso 2, aparecen
anidadas).

15

En algunas aplicaciones es necesario tener exclusi´n mutua entre procesos con la particularidad de que
o
puede haber como mucho n procesos en una secci´n cr´
o
ıtica, con n arbitrario y fijo, pero no necesariamente
igual a la unidad sino posiblemente mayor. Dise˜a una soluci´n para este problema basada en el uso
n
o
de espera ocupada y cerrojos. Estructura dicha soluci´n como un par de subrutinas (usando una misma
o
estructura de datos en memoria compartida), una para el protocolo de entrada y otro el de salida, e incluye
el pseudoc´digo de las mismas.
o

16

Para calcular el n´mero combinatorio
u
n
n(n − 1)(n − 2) . . . (n − k + 1)
( ) =
k
k!
creamos un programa con dos procesos. El proceso P1 calcula el numerador y deposita el resultado en
una variable compartida, denominada x, mientras que P2 calcula el factorial (el denominador) y deposita el
valor en la variable y. Sincroniza los procesos P1 y P2 , utilizando sem´foros, para que el proceso P2 realice
a
correctamente la divisi´n x/y.
o
§
var n : integer := .... ;
k : integer := .... ;
x : integer := 1
;
¦
§
process P1
begin
for i := n-k+1 to n do
x := x * i ;
end
¦

17

¤

¤
§
process P2 ;
var y : integer := 1 ;
begin
for j := 2 to k do
y := y * j ;
¥
print( x/y );
end
¦

¥
¤

¥

Sean los procesos P1 , P2 y P3 , cuyas secuencias de instrucciones son las que se muestran en el cuadro.
Resuelva los siguientes problemas de sincronizaci´n (son independientes unos de otros):
o

creado October 4, 2013- p´gina 84 / 222
a
SCD (13-14). Tema 2. Sincronizaci´n en memoria compartida..
o

a) P2 podr´ pasar a ejecutar e solo si P1 ha ejecutado a o P3 ha ejecutado g.
a

b) P2 podr´ pasar a ejecutar e solo si P1 ha ejecutado a y P3 ha ejecutado g.
a

c) Solo cuando P1 haya ejecutado b, podr´ pasar P2 a ejecutar e y P3 a ejecutar h.
a

d) Sincroniza los procesos de forma que las secuencias b en P1 , f en P2 , y h en P3 , sean ejecutadas como
mucho por dos procesos simult´neamente.
a

§
{ variables globales }
¦
§
process P1 ;
begin
while true do begin
a
b
c
end
end
¦

¤

¤
§
process P2 ;
begin
while true do begin
d
e
f
end
end
¥
¦

¤
§
process P3 ;
begin
while true do begin
g
h
i
end
end
¥
¦

¥
¤

¥

18

Dos procesos P1 y P2 se pasan informaci´n a trav´s de una estructura de datos, ED. Sea un entero, n,
o
e
que indica en todo momento el n´mero de elementos utiles en ED y cuyo valor inicial es 0. El proceso P2
u
´
retira de ED en cada ejecuci´n el ultimo elemento depositado por P1 , y espera si no hay elementos a que P2
o
´
ponga m´s. Sup´n que ED tiene un tama˜o ilimitado, es decir, es lo suficientemente grande para que nunca
a
o
n
se llene. Completa el c´digo de la figura usando sincronizaci´n con sem´foros de forma que el programa
o
o
a
cumpla la funci´n indicada.
o
§
var ED : array[ 0..∞ ] of integer ;
¦
§
process P1 ;
var dato : integer;
begin
while true do begin
dato := calcular();
n := n+1 ;
ED[n] := dato ;
end
end
¦

19

¤

¤
§
process P1 ;
var dato : integer;
begin
while true do begin
dato := ED[n] ;
n := n-1 ;
usar( dato );
end
end
¥
¦

¥
¤

¥

El cuadro que sigue nos muestra dos procesos concurrentes, P1 y P2 , que comparten una variable global x
(las restantes variables son locales a los procesos).

creado October 4, 2013- p´gina 85 / 222
a
SCD (13-14). Tema 2. Sincronizaci´n en memoria compartida..
o

a) Sincronizar los procesos para que P1 use todos los valores x suministrados por P2 .

b) Sincronizar los procesos para que P1 utilice un valor s´ y otro no de la variable x, es decir, utilice los
ı
valores primero, tercero, quinto, etc...

§
{ variables globales }
¦
§
process P1 ;
var m : integer ;
begin
while true do begin
m := 2*x-n ;
print( m );
end
end
¦

¤

¤
§
process P2
var d : integer ;
begin
while true do begin
d := leer_teclado();
x := d-c*5 ;
end
end
¥
¦

¥
¤

¥

20

En la f´brica de bicicletas MountanenBike, tenemos tres operarios que denominaremos OP1 , OP2 y OP3 .
a
OP1 hace ruedas (procedimiento h_rue), OP2 construye cuadros de bicicletas (h_cua), y OP3 , manillares
(h_mani). Un cuarto operario, el Montador, se encarga de tomar dos ruedas (c_rue) , un cuadro (c_cua)
y un manillar (c_man), y de hacer la bicicleta (h_bic). Sincroniza las acciones de los tres operarios y el
montador en los siguientes casos:
a) Los operarios no tienen ning´n espacio para almacenar los componentes producidos, y el Montador no
u
podr´ coger ninguna pieza si ´sta no ha sido fabricada previamente por el correspondiente operario.
a
e

b) Los operarios OP2 y OP3 tienen espacio para almacenar 10 piezas de las que producen, por tanto,
deben esperar si habiendo producido 10 piezas no es retirada ninguna por el Montador. El operador
OP1 tiene espacio para 20 piezas.

§
{ variables globales }
¦
§
process OP1 ;
begin
while true do
begin
h_rue();
end
end
¦

¤

§
¤
process OP2 ;
begin
while true do
begin
h_cua();
end
end
¦
¥

§
¤
process OP3 ;
begin
while true do
begin
h_man();
end
end
¦
¥

§
¤
process OP4 ;
begin
while true do
begin
c_rue();
c_rue();
c_cua();
¥ c_man();
m_bic();
end
end
¦

¥
¤

¥

creado October 4, 2013- p´gina 86 / 222
a
SCD (13-14). Tema 2. Sincronizaci´n en memoria compartida..
o

21

Sentados en una mesa del Restaurante Atreveteacomer, est´n dos personas, cada una de las cuales esta
a
tomando un plato de sopa, y entre las dos comparten una fuente de ensalada. Estas dos personas no tienen
mucha confianza y no pueden comer las dos simult´neamente del plato de ensalada. Se pide:
a
a) Dise˜ar un programa que resuelva el problema.
n

b) Ahora, sup´n que existe un camarero encargado de retirar los platos de sopa cuando ´stos est´n
o
e
a
vac´ es decir, cuando cada una de las personas ha tomado diez cucharadas. Soluciona esta variante
ıos,
teniendo en cuenta que el camarero debe cambiar los platos a las dos personas a la vez.

§

{ variables globales compartidas }
¦
§
¤
§
process Comensal_1 ;
process Comensal_2 ;
begin
begin
while true do begin
while true do begin
tomar_cucharada();
tomar_cucharada();
comer_ensalada();
comer_ensalada();
end
end
end
end
¦
¥
¦

¤

¤
§
{ (apartado b) }
process Camarero ;
begin
while true do begin
quitar_sopa();
poner_sopa();
end
¥
end
¦

¥
¤

¥

22

Aunque un monitor garantiza la exclusi´n mutua, los procedimientos tienen que ser reentrantes. Explicar
o
porqu´.
e

23

Se consideran dos recursos denominados r1 y r2 . Del recurso r1 existen N1 ejemplares y del recurso r2
existen N2 ejemplares. Escribir un monitor que gestione la asignaci´n de los recursos a los procesos de
o
usuario, suponiendo que cada proceso puede pedir:
• Un ejemplar del recurso r1 .
• Un ejemplar del recurso r2 .

• Un ejemplar del recurso r1 y otro del recurso r2 .

La soluci´n deber´ satisfacer estas dos condiciones:
o
a

• Un recurso no ser´ asignado a un proceso que demande un ejemplar de r1 o un ejemplar de r2 hasta
a
que al menos un ejemplar de dicho recurso quede libre.

creado October 4, 2013- p´gina 87 / 222
a
SCD (13-14). Tema 2. Sincronizaci´n en memoria compartida..
o

• Se dar´ prioridad a los procesos que demanden un ejemplar de ambos recursos.
a
• Se asume sem´ntica SU.
a

24

Escribir una soluci´n al problema de lectores-escritores con monitores:
o
a) Con prioridad a los lectores.

b) Con prioridad a los escritores.
c) Con prioridades iguales.

25

Varios coches que vienen del norte y del sur pretenden cruzar un puente sobre un r´ Solo existe un carril
ıo.
sobre dicho puente. Por lo tanto, en un momento dado, el puente solo puede ser cruzado por uno o m´s
a
coches en la misma direcci´n (pero no en direcciones opuestas).
o

a) Completar el c´digo del siguiente monitor que resuelve el problema del acceso al puente suponiendo
o
que llega un coche del norte (sur) y cruza el puente si no hay otro coche del sur (norte) cruzando el
puente en ese momento.
§
Monitor Puente
var

... ;

creado October 4, 2013- p´gina 88 / 222
a

¤
SCD (13-14). Tema 2. Sincronizaci´n en memoria compartida..
o
procedure
begin
...
end
procedure
begin
....
end
procedure
begin
....
end
procedure
begin
...
end

EntrarCocheDelNorte()

SalirCocheDelNorte()

EntrarCocheDelSur()

SalirCocheDelSur()

{ Inicializacion }
begin
....
end
¦

¥

b) Mejorar el monitor anterior, de forma que la direcci´n del trafico a trav´s del puente cambie cada vez
o
e
que lo hayan cruzado 10 coches en una direcci´n, mientras 1 ´ m´s coches estuviesen esperando cruzar
o
o a
el puente en direcci´n opuesta.
o

26

Una tribu de antrop´fagos comparte una olla en la que caben M misioneros. Cuando alg´n salvaje quiere
o
u
comer, se sirve directamente de la olla, a no ser que ´sta est´ vac´ Si la olla est´ vac´ el salvaje despertar´
e
e
ıa.
a
ıa,
a
al cocinero y esperar´ a que ´ste haya rellenado la olla con otros M misioneros.
a
e
Para solucionar la sincronizacion usamos un monitor llamado Olla, que se puede usar as´
ı:
§
monitor Olla ;
....
begin
....
end
¦
§
process ProcSalvaje[ i:1..N ] ;
begin
while true do begin
Olla.Servirse_1_misionero();
Comer(); { es un retraso aleatorio }
end
end
¦

¤
§
process ProcCocinero ;
begin
while true do begin
Olla.Dormir();
Olla.Rellenar_Olla();
end
end
¥
¦

¤

¥
¤

¥

creado October 4, 2013- p´gina 89 / 222
a
SCD (13-14). Tema 2. Sincronizaci´n en memoria compartida..
o

Dise˜a el c´digo del monitor Olla para la sincronizaci´n requerida, teniendo en cuenta que:
n
o
o
• La soluci´n no debe producir interbloqueo.
o

• Los salvajes podr´n comer siempre que haya comida en la olla,
a
• Solamente se despertar´ al cocinero cuando la olla est´ vac´
a
e
ıa.

27

Una cuenta de ahorros es compartida por varias personas (procesos). Cada persona puede depositar o
retirar fondos de la cuenta. El saldo actual de la cuenta es la suma de todos los dep´sitos menos la suma
o
de todos los reintegros. El saldo nunca puede ser negativo.

a) Programar un monitor para resolver el problema, todo proceso puede retirar fondos mientras la cantidad
solicitada c sea menor o igual que el saldo disponible en la cuenta en ese momento. Si un proceso
intenta retirar una cantidad c mayor que el saldo, debe quedar bloqueado hasta que el saldo se
incremente lo suficiente (como consecuencia de que otros procesos depositen fondos en la cuenta)
para que se pueda atender la petici´n. El monitor debe tener 2 procedimientos: depositar(c) y
o
retirar(c). Suponer que los argumentos de las 2 operaciones son siempre positivos. Hacer dos
versiones: uno sin colas de prioridad y otra con colas de prioridad.

b) Modificar la respuesta del apartado anterior, de tal forma que el reintegro de fondos a los clientes sea
servido seg´n un orden FIFO. Por ejemplo, suponer que el saldo es 200 unidades y un cliente est´
u
a
esperando un reintegro de 300 unidades. Si llega otro cliente debe esperarse, incluso si quiere retirar
200 unidades. Resolver el problema usando un monitor con colas de prioridad.

28

Los procesos P1 , P2 ,...,Pn comparten un unico recurso R, pero solo un proceso puede utilizarlo cada vez. Un
´
proceso Pi puede comenzar a utilizar R si est´ libre; en caso contrario, el proceso debe esperar a que el
a
recurso sea liberado por otro proceso. Si hay varios procesos esperando a que quede libre R, se conceder´
a
al proceso que tenga mayor prioridad. La regla de prioridad de los procesos es la siguiente: el proceso
Pi tiene prioridad i, (con 1 ≤ i ≤ n), donde los n´meros menores implican mayor prioridad. Implementar un
u
monitor que implemente los procedimientos Pedir y Liberar.

29

En un sistema hay dos tipos de procesos: A y B. Queremos implementar un esquema de sincronizaci´n en
o
el que los procesos se sincronizan por bloques de 1 proceso del tipo A y 10 procesos del tipo B. De acuerdo
con este esquema:
• Si un proceso de tipo A llama a la operaci´n de sincronizaci´n, y no hay (al menos) 10 procesos de
o
o
tipo B bloqueados en la operaci´n de sincronizaci´n, entonces el proceso de tipo A se bloquea.
o
o

creado October 4, 2013- p´gina 90 / 222
a
SCD (13-14). Tema 2. Sincronizaci´n en memoria compartida..
o

• Si un proceso de tipo B llama a la operaci´n de sincronizaci´n, y no hay (al menos) 1 proceso del tipo
o
o
A y 9 procesos del tipo B (aparte de ´l mismo) bloqueados en la operaci´n de sincronizaci´n, entonces
e
o
o
el proceso de tipo B se bloquea.

• Si un proceso de tipo A llama a la operaci´n de sincronizaci´n y hay (al menos) 10 procesos bloqueados
o
o
en dicha operaci´n, entonces el proceso de tipo A no se bloquea y adem´s deber´n desbloquearse
o
a
a
exactamente 10 procesos de tipo B. Si un proceso de tipo B llama a la operaci´n de sincronizaci´n y
o
o
hay (al menos) 1 proceso de tipo A y 9 procesos de tipo B bloqueados en dicha operaci´n, entonces
o
el proceso de tipo B no se bloquea y adem´s deber´n desbloquearse exactamente 1 proceso del tipo
a
a
A y 9 procesos del tipo B.
• No se requiere que los procesos se desbloqueen en orden FIFO.

los procedimientos para pedir y liberar el recurso

Implementar un Monitor que implemente procedimientos para llevar a cabo la sincronizaci´n requerida entre
o
los diferentes tipos de procesos (el monitor puede exportar una unica operaci´n de sincronizaci´n para todos
´
o
o
los tipos de procesos o una operaci´n espc´
o
ıfica para los de tipo A y otra para los de tipo B.

30

El siguiente monitor (Barrera2) proporciona un unico procedimiento de nombre entrada que provoca que
´
el primer proceso que lo llama sea suspendido y el segundo que lo llama despierte al primero que lo llam´,
o
y as´ act´a c´
ı
u ıclicamente. Obtener una implementaci´n de este monitor usando sem´foros.
o
a

§
Monitor Barrera2 ;

var n : integer;
s : condicion ;

{ num. de proc. que han llegado desde el signal }
{ cola donde espera el segundo
}

procedure entrada() ;
begin
n := n+1 ;
{ ha llegado un proceso mas }
if n<2 then
{ si es el primero:
}
s.wait()
{ esperar al segundo
}
else begin
{ si es el segundo:
}
n := 0;
{ inicializa el contador }
s.signal()
{ despertar al primero }
end
end
{ Inicializacion }
begin
n := 0 ;
end
¦

31

¤

¥

Problema de los fil´sofos-comensales. Sentados a una mesa est´n cinco fil´sofos. La actividad de cada
o
a
o

creado October 4, 2013- p´gina 91 / 222
a
SCD (13-14). Tema 3. Sistemas basados en paso de mensajes..

fil´sofo es un ciclo sin fin de las operaciones de pensar y comer. Entre cada dos fil´sofos hay un tenedor.
o
o
Para comer, un fil´sofo necesita obligatoriamente dos tenedores: el de su derecha y el de su izquierda. Se
o
han definido cinco procesos concurrentes, cada uno de ellos describe la actividad de un fil´sofo. Los procesos
o
usan un monitor, llamado MonFilo.

Antes de comer cada fil´sofo debe disponer de su tenedor de la derecha y el de la izquierda, y cuando
o
termina la actividad de comer, libera ambos tenedores. El fil´sofo i alude al tenedor de su derecha como el
o
n´mero i, y al de su izquierda como el n´mero i + 1 mod 5.
u
u

El monitor MonFilo exportar´ dos procedimentos: coge_tenedor(num_tenedor,num_proceso) y libera_tenedor(n
a
para indicar que un proceso fil´sofo desea coger un tenedor determinado.
o
El c´digo del programa es el siguiente:
o

§
monitor MonFilo ;
....
begin
....
end

¤

process Filosofo[ i: 0..4 ] ;
begin
while true do begin
MonFilo.coge_tenedor(i,i);
{ argumento 1=codigo tenedor }
MonFilo.coge_tenedor(i+1 mod 5, i); { argumento 2=numero de proceso }
comer();
MonFilo.libera_tenedor(i,i);
MonFilo.libera_tenedor(i+1 mod 5,i);
pensar();
end
end
¦

Dise˜a el monitor MonFilo, compartido por todos los procesos fil´sofos. Para evitar interbloqueo (que ocurre
n
o
si todos los fil´sofos toman el tenedor a su izquierda antes de que ninguno de ellos pueda coger el tenedor
o
de la derecha), la soluci´n no debe permitir que haya m´s de cuatro fil´sofos simult´neamente intentado
o
a
o
a
coger un tenedor

creado October 4, 2013- p´gina 92 / 222
a

¥
Chapter 4

Tema 3. Sistemas basados en paso de
mensajes.
4.1

4.1.1

Mecanismos b´sicos en sistemas basados en paso de mensajes
a
Introducci´n
o

Introducci´n. Multiprocesador con mem. compartida vs. Sistema Distribuido
o

• Multiprocesador:

◾ M´s f´cil programaci´n (variables compartidas): se usan mecanismos como cerrojos, sem´foros y
a a
o
a
monitores.
◾ Implementaci´n m´s costosa y escalabilidad hardware limitada: el acceso a memoria com´n
o
a
u
supone un cuello de botella.

• Sistema Distribuido:

◾ Distribuci´n de datos y recursos.
o

◾ Soluciona el problema de la escalabilidad y el elevado coste.

◾ Mayor dificultad de programaci´n: No hay direcciones de memoria comunes y mecanismos como
o
los monitores son inviables.
93
SCD (13-14). Tema 3. Sistemas basados en paso de mensajes..
Necesidad de una notaci´n de progr. distribuida
o
• Lenguajes tradicionales (memoria com´n)
u

◾ Asignaci´n: Cambio del estado interno de la m´quina.
o
a

◾ Estructuraci´n: Secuencia, repetici´n, alternaci´n, procedimientos, etc.
o
o
o

• Extra a˜adido: Env´ / Recepci´n
n
ıo
o

⇒ Afectan al entorno externo.

◾ Son tan importantes como la asignaci´n.
o

◾ Permiten comunicar procesos que se ejecutan en paralelo.

• Paso de mensajes:

◾ Abstracci´n: Oculta Hardware (red de interconexi´n).
o
o

◾ Portabilidad: Se puede implementar eficientemente en cualquier arquitectura (multiprocesador o
plataforma distribuida).

4.1.2

◾ No requiere mecanismos para asegurar la exclusi´n mutua.
o

Vista logica arquitectura y modelo de ejecuci´n
o

Vista logica de la arquitectura

• N procesos, cada uno con su espacio de direcciones propio (memoria).

• En un mismo procesador podr´ residir f´
ıan
ısicamente varios procesos, aunque es muy com´n la ejecuci´n
u
o
1 proceso-procesador.
• Los procesos se comunican mediante env´ y recepci´n de mensajes.
ıo
o

• Cada interacci´n requiere cooperaci´n entre 2 procesos: el propietario de los datos (emisor) debe
o
o
intervenir aunque no haya conexi´n l´gica con el evento tratado en el receptor.
o o

creado October 4, 2013- p´gina 94 / 222
a
SCD (13-14). Tema 3. Sistemas basados en paso de mensajes..
Estructura de un programa de paso de mensajes. SPMD

• Ejecutar un programa diferente sobre cada proceso puede ser algo dif´ de manejar.
ıcil
• Enfoque com´n: Estilo SPMD (Single Program Multiple Data).
u

◾ El c´digo que ejecutan los diferentes procesos es id´ntico, pero sobre datos diferentes.
o
e

◾ El c´digo incluye la l´gica interna para que cada tarea ejecute lo que proceda dependiendo de
o
o
la identidad del proceso.
§
{ ejemplo: Proceso[0] envia y Proceso[1] recibe }
process Proceso[ nump : 0..1 ];
begin
if nump = 0 then begin {si soy 0}
dato := Produce();
send( dato, Proceso[1]);
end else begin {si soy 1}
receive( dato, Proceso[0] );
Consume( dato );
end
end
¦

Estructura de un programa de paso de mensajes. MPMD
• Estilo MPMD (Multiple Program Multiple Data):

◾ Cada proceso ejecuta el mismo o diferentes programas de un conjunto de ficheros objeto ejecutables.
◾ Los diferentes procesos pueden usar datos diferentes.

4.1.3

Primitivas b´sicas de paso de mensajes
a

Primitivas b´sicas de paso de mensajes
a

• Env´ send(expresion,identi f icador proceso destino)
ıo:

creado October 4, 2013- p´gina 95 / 222
a

¤

¥
SCD (13-14). Tema 3. Sistemas basados en paso de mensajes..
• Recepci´n: receive(variable,identi f icador proceso origen)
o

Las primitivas send y receive permiten:

• Comunicaci´n: Los procesos env´
o
ıan/reciben mensajes en lugar de escribir/leer en variables compartidas.

• Sincronizaci´n: la recepci´n de un mensaje es posterior al env´ Generalmente, la recepci´n supone
o
o
ıo.
o
la espera del mensaje por parte del receptor.

Esquemas de identificaci´n de la comunicaci´n
o
o

¿C´mo identifica el emisor al receptor del mensaje y viceversa?
o
Existen dos posibilidades:
Denominaci´n directa
o

• Emisor identifica expl´
ıcitamente al receptor y viceversa.
• Se utilizan los identificadores de los procesos.

Denominaci´n indirecta
o

Los mensajes se depositan en almacenes intermedios que son globales a los procesos (buzones).
Denominaci´n directa
o

• Ventaja principal: No hay retardo para establecer la identificaci´n.
o
• Inconvenientes:

◾ Cambios en la identificaci´n requieren recompilar el c´digo.
o
o
◾ S´lo permite enlaces 1-1.
o

creado October 4, 2013- p´gina 96 / 222
a
SCD (13-14). Tema 3. Sistemas basados en paso de mensajes..
§
process P0 ;
var dato : integer ;
begin
dato := Produce();
send( dato, P1 );
end
¦

¤
§
process P1 ;
var midato : integer ;
begin
receive( midato, P0 );
Consume( midato );
end
¥
¦

¤

¥

• Existen esquemas asim´tricos: el emisor identifica al receptor, pero el receptor no indica emisor:
e
◾ receive(variable,id origen): en id origen se devuelve el emisor del mensaje.

◾ receive(variable,ANY): ANY indica que se puede recibir de cualquier emisor.

Denominaci´n indirecta
o

• Presenta una mayor flexibilidad al permitir la comunicaci´n simult´nea entre varios procesos.
o
a
• Declaraci´n est´tica/din´mica:
o
a
a

◾ Est´tica: fija fuente/destino en tiempo de compilaci´n. No apropiada en entornos cambiantes.
a
o
◾ Din´mica: m´s potente pero menos eficiente
a
a

§
var buzon : channel of integer ;
¦
§
process P0 ;
var dato : integer ;
begin
dato := Produce();
send( dato, buzon );
end
¦

¤
§
process P1 ;
var midato : integer ;
begin
receive( midato, buzon );
Consume( midato );
end
¥
¦

¤
¥
¤

¥

Denominaci´n indirecta (2)
o

• Existen tres tipos de buzones: canales (uno a uno), puertos (muchos a uno) y buzones generales
(muchos a muchos).

creado October 4, 2013- p´gina 97 / 222
a
SCD (13-14). Tema 3. Sistemas basados en paso de mensajes..

Comportamiento de las operaciones de paso de mensajes

• El comportamiento de las operaciones puede variar dependiendo de las necesidades. Ejemplo:
§
process Emisor ;
var a : integer := 100 ;
begin
send( a, Receptor ) ;
a := 0 ;
end
¦

¤
§
process Receptor ;
var b : integer ;
begin
receive( b, Emisor ) ;
imprime( b );
end
¥
¦

¤

¥

• El comportamiento esperado del send impone que el valor recibido en b sea el que ten´ a (100) justo
ıa
antes de la llamada a send.

• Si se garantiza esto, se habla de comportamiento seguro (se habla de que el programa de paso de
mensajes es seguro).

• Generalmente, un programa no seguro (en el ejemplo, si pudiera recibirse 0 en lugar de 100), se
considera incorrecto, aunque existen situaciones en las que puede interesar usar operaciones que no
garantizan dicha seguridad.

Instantes cr´
ıticos en las operaciones de paso de mensajes
§
process Emisor ;
var a : integer := 100 ;
begin
send( a, Receptor ) ;
a := 0 ;
end
¦

Instantes relevantes en el emisor:

¤
§
process Receptor ;
var b : integer ;
begin
receive( b, Emisor ) ;
imprime( b );
end
¥
¦

¤

¥

creado October 4, 2013- p´gina 98 / 222
a
SCD (13-14). Tema 3. Sistemas basados en paso de mensajes..

• E1 : Emisor acaba de indicar al Sistema de Paso de Mensajes (SPM) la direccion de a y el identificador
del Receptor.

• E2 : SPM comienza la lectura de datos en a.

• E3 : SPM termina de leer todos los datos en a.

Instantes relevanetes en el receptor:

• R1 : Receptor acaba de indicar al SPM la direccion de b y el identificador del Emisor.
• R2 : SPM comienza a escribir en b.
• R3 : SPM termina de escribir en b.

Ordenaci´n de los instantes relevantes
o

Los eventos relevantes citados deben ocurrir en cierto orden:

• El emisor puede comenzar el envio antes que el receptor, o al rev´s. Es decir, no hay un orden temporal
e
entre E1 y R1 (se cumple E1 <= R1 o R1 <= E1 ).

• L´gicamente, los tres eventos del emisor se producen en orden, y tambi´n los tres del receptor. Se
o
e
cumple que: E1 < E2 < E3 y tambi´n que R1 < R2 < R3 .
e
• Antes de que se escriba el primer byte en el receptor, se debe haber comenzado ya la lectura en el
emisor, por tanto E2 < R2 .

• Antes de que se acaben de escribir los datos en el receptor, se deben haber acabado de leer en el
emisor, es decir E3 < R3 .
• Por transitividad se puede demostrar que R3 es siempre el ´ltimo evento.
u

Mensajes en tr´nsito
a

Por la hip´tesis de progreso finito, el intervalo de tiempo entre E1 y R3 tiene una duraci´n no predecible.
o
o
Entre E1 y R3 , se dice que el mensaje est´ en tr´nsito.
a
a

a
e
• El SPM necesita usar memoria temporal para todos los mensajes en tr´nsito que est´ gestionando en
un momento dado.
• La cantidad de memoria necesaria depender´ de diversos detalles (tama˜o y n´mero de los mensajes
a
n
u
en tr´nsito, velocidad de la transmisi´n de datos, pol´
a
o
ıticas de envio de mensajes, etc... )
• Dicha memoria puede estar ubicada en el nodo emisor y/o en el receptor y/o en nodos intermedios, si
los hay.
• En un momento dado, el SPM puede detectar que no tiene suficiente memoria para almacenamiento
temporal de datos durante el envio (debe retrasar la lectura en el emisor hasta asegurarse que hay
memoria para enviar los datos)

creado October 4, 2013- p´gina 99 / 222
a
SCD (13-14). Tema 3. Sistemas basados en paso de mensajes..
Seguridad de las operaciones de paso de mensajes

Las operaciones de env´ y/o recepci´n podr´ no ser seguras, es decir, el valor que el emisor pretend´
ıo
o
ıan
ıa
enviar podr´ no ser el mismo que el receptor finalmente recibe, ya que se usan zonas de memoria, accesibles
ıa
desde los procesos involucrados, que podr´ escribirse cuando el mensaje est´ en tr´nsito.
ıan
a
a

• Operaci´n de env´
o
ıo-recepci´n segura: Ocurre cuando se puede garantizar a priori que el valor de a
o
en E1 coincidir´ con el valor de b justo tras R3 .
a
• Operaci´n de env´
o
ıo-recepci´n insegura: Una operaci´n puede ser no segura en dos circunstancias:
o
o
◾ se puede modificar el valor de a entre E1 y E3 (env´ inseguro)
ıo

◾ se puede modificar el valor de b entre R2 y R3 (recepci´n insegura).
o

Tipos de operaciones de paso de mensajes

Operaciones seguras

• Devuelven el control cuando se garantiza la seguridad.

• No siempre significa que el receptor haya recibido el dato cuando finalice el send, sino que cambiar
los datos no viola la seguridad.
• Existen 2 mecanismos de paso de mensajes seguro:
◾ Env´ y recepci´n s´
ıo
o ıncronos.
◾ Env´ as´
ıo ıncrono seguro

Operaciones inseguras

• Devuelven el control de forma inmediata sin garantizar la seguridad.

• Es responsabilidad del usuario asegurar que no se alteran los datos mientras el mensaje est´ en
a
tr´nsito.
a
• Deben existir sentencias adicionales para comprobar el estado de la operaci´n.
o

El est´ndar MPI incluye funciones con todas estos comportamientos.
a

Operaciones s´
ıncronas. Comportamiento

§
¦

s send( variable , id proceso receptor ) ;

¥

• Realiza el env´ de los datos y espera bloqueado hasta que los datos hayan terminado de escribirse
ıo
en la memoria local designada por el proceso receptor en su llamada a la operaci´n de recepci´n.
o
o
• Es decir: devuelve el control despu´s de R3 .
e

¤

creado October 4, 2013- p´gina 100 / 222
a
SCD (13-14). Tema 3. Sistemas basados en paso de mensajes..

§

¤

¦

¥

receive ( variable , id proceso emisor ) ;

• Espera bloqueado hasta que el emisor emita un mensaje con destino al proceso receptor (si no lo hab´
ıa
hecho ya), y hasta que hayan terminado de escribirse los datos en la zona de memoria designada en
variable.
• Es decir: devuelve el control despu´s de R3 .
e

Operaciones s´
ıncronas. Cita

• Exige cita entre emisor y receptor: La operaci´n s_send no devuelve el control hasta que el receive
o
correspondiente sea alcanzado en el receptor
◾ El intercambio de mensaje constituye un punto de sincronizaci´n entre emisor y receptor.
o
◾ El emisor podr´ hacer aserciones acerca del estado del receptor.
a
◾ An´logo: comunicaci´n telef´nica y chat.
a
o
o

Operaciones s´
ıncronas. Desventajas

• F´cil de implementar pero poco flexible.
a

• Sobrecarga por espera ociosa: adecuado s´lo cuando send/receive se inician aprox. mismo tiempo.
o
• Interbloqueo: es necesario alternar llamadas en intercambios (c´digo menos legible).
o
Ejemplo de Interbloqueo

§
{ P0 }
s_send( a, P1 );
receive( b, P0 );
¦

Correcci´n
o

¤

§
{ P0 }
s_send( a, P1 );
receive( b, P0 );
¦

¤

¥

¥

§
{ P1 }
s_send( a, P0 );
receive( b, P1 );
¦

¤

§
{ P1 }
receive( b, P1 );
s_send( a, P0 );
¦

¤

¥

¥

creado October 4, 2013- p´gina 101 / 222
a
SCD (13-14). Tema 3. Sistemas basados en paso de mensajes..
Env´ as´
ıo ıncrono seguro (1)

§
¦

¤

send( variable , id proceso receptor ) ;

¥

• Inicia el env´ de los datos designados y espera bloqueado hasta que hayan terminado de leerse todos
ıo
los datos de variable en una memoria local del Emisor (buffer). Tras la copia de datos a memoria
local, devuelve el control sin que tengan que haberse recibido los datos en el receptor.

• Por tanto, devuelve el control despu´s de E3 .
e

• Se suele usar junto con la recepci´n s´
o ıncrona (receive).

Env´ as´
ıo ıncrono seguro. Ventajas e Inconvenientes

• Alivia sobrecargas de espera ociosa a costa de gesti´n de almacenamiento temporal (buffer).
o

• S´lo menos ventajosas en programas altamente s´
o
ıncronos o cuando la capacidad del buffer sea un
asunto cr´
ıtico.
• Impacto del buffer finito: Se deben escribir programas con requisitos de almacenamiento acotados.

◾ Si P1 es m´s lento que P0, P0 podr´ continuar siempre que hubiese buffer. Si el buffer se agota,
a
ıa
P0 se bloquear´
ıa.

§
{ P0 } for i:=1 to 10000 do begin
a := Produce() ;
send( a, P1 ) ;
end
¦

¤
§
{ P1 } for i:=1 to 10000 do begin
receive( a, P0 ) ;
Consume( a ) ;
end
¥
¦

• Interbloqueo con buffer: No olvidar que las llamadas a receive siguen siendo s´
ıncronas.
§
{ P0 } receive( b, P1 );
send( a, P1 );
¦

¤
¥

§
receive( b, P0 ); { P1 }
send( a, P0 );
¦

¤
¥

creado October 4, 2013- p´gina 102 / 222
a

¤

¥
SCD (13-14). Tema 3. Sistemas basados en paso de mensajes..
Operaciones inseguras

• Operaciones seguras: Garantizan la seguridad, pero presentan ineficiencias:
◾ sobrecarga de espera ociosa (sin buffer).

◾ sobrecarga de gesti´n de buffer (con buffer).
o

• Alternativa: Requerir que el programador asegure la correcci´n y usar operaciones send/receive
o
con baja sobrecarga.
◾ Las operaciones devuelven el control antes de que sea seguro modificar (en el caso del env´ o
ıo)
leer los datos (en el caso de la reepci´n).
o
◾ Es responsabilidad del usuario asegurar que el comportamiento es correcto.

◾ Deben existir sentencias de chequeo de estado: indican si los datos pueden alterarse o leerse
sin comprometer la seguridad.
◾ Una vez iniciada la operaci´n, el usuario puede realizar cualquier c´mputo que no dependa de la
o
o
finalizaci´n de la operaci´n y, cuando sea necesario, chequear´ el estado de la operaci´n.
o
o
a
o

Paso de mensajes as´
ıncrono inseguro. Operaciones

§
¦

i send( variable , id proceso receptor , var resguardo ) ;

¤
¥

• Indica al SPM que comienze una operaci´n de env´ al proceso receptor designado. No espera a que
o
ıo
terminen de leerse los bytes del emisor, ni a que terminen de escribirse en el receptor.
• Es decir: devuelve el control despu´s de E1 .
e

§
¦

• var resguardo permite consultar el estado del env´
ıo.

¤

i receive ( variable , id proceso receptor , var resguardo ) ;

¥

• Indica al SPM que el proceso receptor desea recibir en la zona de memoria local designada en variable
un mensaje del proceso emisor indicado. Se devuelve el control sin esperar a que se complete el env´
ıo
ni a que llegen los datos.

• Es decir: devuelve el control despu´s de R1 .
e

• var resguardo permite consultar despu´s el estado de la recepci´n.
e
o

Esperar el final de operaciones as´
ıncronas

Cuando un proceso hace i_send o i_receive puede continuar trabajando hasta que llega un momento en
el que debe esperar a que termine la operaci´n. Para esto se disponen de estos dos procedimientos:
o

§
¦

wait send( var resguardo ) ;

creado October 4, 2013- p´gina 103 / 222
a

¤
¥
SCD (13-14). Tema 3. Sistemas basados en paso de mensajes..
§
¦

• Se invoca por el proceso emisor, y lo bloquea hasta que la operaci´n de env´ asociada a var resguardo
o
ıo
ha llegado al instante E3 .

wait recv ( var resguardo ) ;

• Se invoca por el proceso receptor, que queda bloqueado hasta que la operaci´n de recepci´n asociada
o
o
a var resguardo ha llegado al instante R3 .

Paso de mensajes as´
ıncrono inseguro (no bloqueante)

• El proceso que ejecuta i_send informa al SPM de un mensaje pendiente y contin´a.
u
◾ El programa puede hacer mientras otro trabajo (trabajo_util)
◾ El SPM iniciar´ la comunicaci´n cuando corresponda.
a
o

◾ Operaciones de chequeo indican si es seguro tocar/leer los datos.

• Mejora: El tiempo de espera ociosa se puede emplear en computaci´n
o
• Coste: Reestructuraci´n programa, mayor esfuerzo del programador.
o

§
process Emisor ;
var a : integer := 100 ;
begin
i_send( a, Receptor, resg );
{ trabajo util : no escribe en ’ a’}
trabajo_util_emisor();
wait_send(resg);
a := 0 ;
end
¦

¤
§
process Receptor ;
var b : integer ;
begin
i_receive( b, Emisor, resg );
{ trabajo util : no accede a ’ b’}
trabajo_util_receptor();
wait_recv (resg);
imprime( b );
end
¥
¦

Ejemplo: Productor-Consumidor con paso as´
ıncrono

Se logra simultanear transmisi´n, producci´n y consumici´n:
o
o
o
§
process Productor ;
var x, x_env : integer ;
begin
x := Producir()
while true do begin
x_env := x ;
i_send(x_env,Consumidor,resg);
x := Producir() ;
wait_send(resg);
end
end
¦

¤
§
process Consumidor ;
var y, y_rec : integer ;
begin
i_receive(y_rec,Productor,resg);
while true do begin
wait_recv(resg);
y := y_rec ;
i_receive(y_rec,Productor,resg);
Consumir(y);
end
end
¥
¦

¤

¥

¤

¥

creado October 4, 2013- p´gina 104 / 222
a

¤
¥
SCD (13-14). Tema 3. Sistemas basados en paso de mensajes..
Limitaciones:

• La duraci´n del trabajo util podr´ ser muy distinta de la de cada transmisi´n.
o
ıa
o
• Se descarta la posibilidad de esperar m´s de un posible emisor.
a

Consulta de estado de operaciones as´
ıncronas

Para solventar los dos problemas descritos, se pueden usar dos funciones de comprobaci´n de estado de una
o
transmisi´n de un mensaje. No suponen bloqueo, solo una consulta:
o

§
¦

§
¦

test send ( var resguardo ) ;

• Funci´n l´gica que se invoca por el emisor. Si el env´ asociado a var resguardo ha llegado a E3 ,
o o
ıo
devuelve true, sino devuelve false.
test recv ( var resguardo) ;

• Funci´n l´gica que se invoca por el receptor. Si el env´ asociado a var resguardo ha llegado a R3 ,
o o
ıo
devuelve true, sino devuelve false.

Paso as´
ıncrono con espera ocupada posterior.

El trabajo util de nuevo se puede simult´near con la transmisi´n del mensaje, pero en este caso dicho debe
a
o
descomponerse en muchas tareas peque˜as.
n
§
process Emisor ;
var a : integer := 100 ;
begin
i_send( a, Receptor, resg );
while not test_send( resg ) do
{ trabajo util : no escribe en ’ a’}
trabajo_util_emisor();
a := 0 ;
end
¦

¤
§
process Receptor ;
var b : integer ;
begin
i_receive( b, Emisor, resg );
while not test_recv( resg ) do
{ trabajo util : no accede a ’ b’}
trabajo_util_receptor();
imprime( b );
end
¥
¦

¤

¥

Si el trabajo util es muy corto, puede convertirse en una espera ocupada que consume much´
ısima CPU
in´tilmente. Es complejo de ajustar bien.
u
Recepci´n simult´nea de varios emisores.
o
a

En este caso se comprueba continuamente si se ha recibido un mensaje de uno cualquiera de dos emisores,
y se espera hasta que se han recibido de los dos:
creado October 4, 2013- p´gina 105 / 222
a

¤
¥

¤
¥
SCD (13-14). Tema 3. Sistemas basados en paso de mensajes..
§
process Emisor1 ;
var a :integer:= 100;
begin
send(a,Receptor);
end
process Emisor2 ;
var b :integer:= 200;
begin
send(b,Receptor);
end
¦

4.1.4

¤§
process Receptor ;
var b1, b2 : integer ;
r1,r2 : boolean := false ;
begin
i_receive( b1, Emisor1, resg1 );
i_receive( b2, Emisor2, resg2 );
while not r1 or not r2 do begin
if not r1 and test_recv( resg1 ) then begin
r1 := true ;
imprime(" recibido de 1 : ", b1 );
end
¥
if not r2 and test_recv( resg2 ) then begin
r2 := true ;
imprime(" recibido de 2 : ", b2 );
end
end
end
¦

¤

¥

Espera selectiva

Espera Selectiva. Introducci´n al problema
o

• Los modelos basados en paso de mensajes imponen ciertas restricciones.

• No basta con send y receive para modelar el comportamiento deseado.

Productor-Consumidor con buffer de tama˜o fijo
n
• Se asumen operaciones s´
ıncronas.

• Problema: Acoplamiento forzado entre los procesos.

§
process Productor ;
begin
while true do begin
v := Produce();
s_send(v,Consumidor);
end
end
¦

¤

¥

§
process Consumidor ;
begin
while true do begin
receive(v,Productor);
Consume(v);
end
end
¦

¤

¥

Introducci´n al problema. Mejora
o

• Mejora: Gesti´n intercambio mediante proceso Buffer.
o
◾ Productor puede continuar despu´s env´
e
ıo.

◾ Problema: El buffer s´lo puede esperar mensajes de un unico emisor en cada instante.
o
´

creado October 4, 2013- p´gina 106 / 222
a
SCD (13-14). Tema 3. Sistemas basados en paso de mensajes..
• Aspecto com´n en aplicaciones cliente-servidor.
u

◾ No se conoce a priori el cliente que hace la petici´n en cada instante.
o
◾ Servidor debe estar preparado para recibir sin importar orden.

§
{ Productor (P) }
process P ;
begin
while true do begin
v:=Produce();
s_send(v,B);
end
end
¦

¤

¥

§
{ Buffer (B) }
process B ;
begin
while true do begin
receive(v,P);
receive(s,C);
s_send(v,C);
end
end
¦

¤

¥

§
{ Consumidor (C) }
process C ;
begin
while true do begin
s_send(s,B);
receive(v,B);
Consume(v);
end
end
¦

¤

¥

Espera selectiva con alternativas guardadas (1)

Soluci´n: usar espera selectiva con varias alternativas guardadas. Es una nueva sentencia compuesta, con
o
la siguiente sintaxis:
§
select
when condicion1 receive( variable1 , proceso1 ) do
sentencias1
when condicion2 receive( variable2 , proceso2 ) do
sentencias2
⋯
when condicionn receive( variablen , proceson ) do
sentenciasn
end
¦

¤

¥

• Cada bloque que comienza en when se llama una alternativa.

• En cada alternativa, el texto desde when hasta do se llama la guarda de dicha alternativa, la guarda
puede incluir una expresi´n l´gica (condicioni )
o o
• Los receive nombran a otros procesos del programa concurrente (procesoi ), y cada uno referencia una
variable local (variablei ), donde eventualmente se recibir´ un valor del proceso asociado.
a

Sintaxis de las guardas.

En una guarda de una orden select:

• La expresi´n l´gica puede omitirse, es ese caso la sintaxis ser´
o o
ıa:
§
when receive( mensaje, proceso ) do
sentencias
¦

que es equivalente a:

¤
¥

creado October 4, 2013- p´gina 107 / 222
a
SCD (13-14). Tema 3. Sistemas basados en paso de mensajes..

§
when true receive( mensaje, proceso ) do
sentencias
¦

• La sentencia receive puede no aparecer, la sintaxis es:
§
when condicion do
sentencias
¦

¤
¥

¤
¥

decimos que esta es una guarda sin sentencia de entrada.

Guardas ejecutables. Evaluaci´n de las guardas.
o

Una guarda es ejecutable en un momento de la ejecuci´n de un proceso P cuando se dan estas dos condio
ciones:
• La condici´n de la guarda se eval´a en ese momento a true.
o
u

• Si tiene sentencia de entrada, entonces el proceso origen nombrado ya ha iniciado en ese momento
una sentencia send (de cualquier tipo) con destino al proceso P, que casa con el receive.

Una guarda ser´ potencialmente ejecutable si se dan estas dos condiciones:
a
• La condici´n de la guarda se eval´a a true.
o
u

• Tiene una sentencia de entrada, sentencia que nombra a un proceso que no ha iniciado a´n un send
u
hacia P.

Una guarda ser´ no ejecutable en el resto de los casos, en los que forzosamente la condici´n de la guarda
a
o
se eval´a a false.
u
Evaluaci´n de las guardas.
o

Cuando el flujo de control llega a un select, se eval´an las condiciones de todas las guardas, y se verifica
u
el estado de todos los procesos nombrados en los receive. De esta forma se clasifican las guardas, y se
selecciona una alternativa:
• Si hay guardas ejecutables con sentencia de entrada: se selecciona aquella cuyo send se inici´ antes
o
(esto garantiza a veces la equidad).

• Si hay guardas ejecutables, pero ninguna tiene una sentencia de entrada: se selecciona aleatoriamente
una cualquiera.
• Si no hay ninguna guarda ejecutable, pero s´ hay guardas potencialmente ejecutables: se espera
ı
(bloqueado) a que alguno de los procesos nombrados en esas guardas inicie un send, en ese momento
acaba la espera y se selecciona la guarda correspondiente a ese proceso.

• Si no hay guardas ejecutables ni potencialmente ejecutables: no se selecciona ninguna guarda.

creado October 4, 2013- p´gina 108 / 222
a
SCD (13-14). Tema 3. Sistemas basados en paso de mensajes..
Ejecuci´n de un select
o

Para ejecutar un select primero se intenta seleccionar una guarda de acuerdo con el esquema descrito arriba.

• Si no se puede seleccionar ninguna guarda, no se hace nada (no hay guardas ni ejecutables, ni
potencialmente ejecutables).
• Si se ha podido seleccionar una guarda, entonces se dan estos dos pasos en secuencia:

1. Si esa guarda tiene sentencia de entrada, se ejecuta el receive (siempre habr´ un send iniciado),
a
y se recibe el mensaje.
2. Se ejecuta la sentencia asociada a la alternativa.

y despu´s finaliza la ejecuci´n del select.
e
o

Hay que tener en cuenta que select conlleva potencialmente esperas, y por tanto se pueden producir
esperas indefinidas (interbloqueo).

Existe select con prioridad: la selecci´n no ser´ arbitraria (el orden en el que aparecen las alternativas
o
ıa
establece la prioridad).
Productor-Consumidor con buffer limitado

• Buffer no conoce a priori orden de peticiones (Inserci´n/Extracci´n).
o
o

• Las guardas controlan las condiciones de sincronizaci´n (seguridad).
o
§
{ Productor (P) }
while true do
begin
v:=Produce();
s_send(v,B);
end
¦

¤

¥

§
{ Buffer (B) }
var esc, lec, cont : integer := 0 ;
buf : array[0..tam-1] of integer ;
begin
while true do
select
when cont<=tam receive(v,P) do
buf[esc]:= v ;
esc := (esc+1) mod tam ;
cont := cont+1 ;
when cont ≠ 0 receive(s,C) do
s_send(buf[lec],C);
esc := (esc+tam-1) mod tam ;
cont := cont-1 ;
end
end
¦

¤

§
{ Consumidor (C) }
while true do
begin
s_send(s,B);
receive(v,B);
Consume(v);
end
¦

¤

¥

¥

Select con guardas indexadas

A veces es necesario replicar una alternativa. En estos casos se puede usar una sintaxis que evita reescribir
el c´digo muchas veces, con esta sintaxis:
o
creado October 4, 2013- p´gina 109 / 222
a
SCD (13-14). Tema 3. Sistemas basados en paso de mensajes..

§
for indice := inicial to f inal
when condicion receive( mensaje, proceso ) do
sentencias
¦

¥

Tanto la condici´n, como el mensaje, el proceso o la sentencia pueden contener referencias a la variable
o
indice (usualmente es i o j). Es equivalente a:

§
when condicion receive( mensaje,
sentencias { se sustituye indice
when condicion receive( mensaje,
sentencias { se sustituye indice
⋯
when condicion receive( mensaje,
sentencias { se sustituye indice
¦

¤

proceso ) do
por inicial }
proceso ) do
por inicial + 1 }
proceso ) do
por f inal }

¤

¥

Ejemplo de select con guardas indexadas

A modo de ejemplo, si suma es un vector de n enteros, y fuente[0], fuente[1], etc... son n procesos,
entonces:

§
for i := 0 to n-1
when suma[i] < 1000 receive( numero, fuente[i] ) do
suma[i] := suma[i] + numero ;
¦

Es equivalente a:

§
when suma[0] < 1000 receive( numero, fuente[0] ) do
suma[0] := suma[0] + numero ;
when suma[1] < 1000 receive( numero, fuente[1] ) do
suma[1] := suma[1] + numero ;
⋯
when suma[n-1] < 1000 receive( numero, fuente[n − 1] ) do
suma[n-1] := suma[n-1] + numero ;
¦

¤

¥
¤

¥

En un select se pueden combinar una o varias alternativas indexadas con alternativas normales no indexadas.
Ejemplo de select

Este ejemplo suma los primeros numeros recibidos de cada uno de los n procesos fuente hasta que cada
suma iguala o supera al valor 1000:

§
var suma
: array[0..n-1] of integer := (0,0,...,0) ;
continuar : boolean := false ;
numero
: integer ;
begin
while continuar do begin
continuar := false ; { terminar cuando ∀i suma[i] ≥ 1000 }
select
for i := 0 to n − 1
when suma[i] < 1000 receive( numero, fuente[i] ) do

creado October 4, 2013- p´gina 110 / 222
a

¤
SCD (13-14). Tema 3. Sistemas basados en paso de mensajes..
end
end

suma[i] := suma[i]+numero ; { sumar }
continuar := true ; { iterar de nuevo }

end
¦

¥

aqu´ hemos supuesto que los procesos fuente est´n definidos como:
ı
a

§
process fuente[ i : 0..n − 1 ] ;
begin
.....
end
¦

4.2

4.2.1

¥

Paradigmas de interacci´n de procesos en programas distribuidos
o
Introducci´n
o

Introducci´n
o

Paradigma de interacci´n
o

Un paradigma de interacci´n define un esquema de interacci´n entre procesos y una estructura de control
o
o
que aparece en m´ltiples programas.
u

• Unos pocos paradigmas de interacci´n se utilizan repetidamente para desarrollar muchos programas
o
distribuidos.
• Veremos los siguientes paradigmas de interacci´n:
o
1. Maestro-Esclavo.

2. Iteraci´n s´
o ıncrona.

3. Encauzamiento (pipelining).
4. Cliente-Servidor.

• Se usan principalmente en programaci´n paralela, excepto el ultimo que es m´s general (sistemas
o
a
distribuidos) y se ver´ en el siguiente apartado del cap´
a
ıtulo (Mecanismos de alto nivel para paso de
mensajes).

4.2.2

¤

Maestro-Esclavo

Maestro-Esclavo

• En este patr´n de interacci´n intervienen dos entidades: un proceso maestro y m´ltiples procesos
o
o
u
esclavos.
• El proceso maestro descompone el problema en peque˜as subtareas (que guarda en una colecci´n),
n
o
las distribuye entre los procesos esclavos y va recibiendo los resultados parciales de estos, de cara a
producir el resultado final.

creado October 4, 2013- p´gina 111 / 222
a
SCD (13-14). Tema 3. Sistemas basados en paso de mensajes..

• Los procesos esclavos ejecutan un ciclo muy simple hasta que el maestro informa del final del c´mputo:
o
reciben un mensaje con la tarea , procesan la tarea y env´ el resultado al maestro.
ıan

Ejemplo: C´lculo del Conjunto de Mandelbrot
a

• Conjunto de Mandelbrot: Conjunto de puntos c del plano complejo (dentro de un c´
ırculo de radio
2 centrado en el origen) que no exceder´n cierto l´
a
ımite cuando se calculan realizando la siguiente
iteraci´n (inicialmente z = 0 con z = a + bi ∈ C):
o
Repetir zk+1 = zk 2 + c

hasta

z > 2 o k > l´
ımite

• Se asocia a cada pixel (con centro en el punto c) un color en funci´n del n´mero de iteraciones (k)
o
u
necesarias para su c´lculo.
a

• Conjunto soluci´n= {pixels que agoten iteraciones l´
o
ımite dentro de un c´
ırculo de radio 2 centrado en
el origen}.

Ejemplo: C´lculo del Conjunto de Mandelbrot
a

• Paralelizaci´n sencilla: Cada pixel se puede calcular sin ninguna informaci´n del resto
o
o

• Primera aproximaci´n: asignar un n´mero de pixels fijo a cada proceso esclavo y recibir resultados.
o
u

◾ Problema: Algunos procesos esclavos tendr´ m´s trabajo que otros (el n´mero de iteraciones
ıan a
u
por pixel no es fijo) para cada pixel.

• Segunda aproximaci´n:
o

creado October 4, 2013- p´gina 112 / 222
a
SCD (13-14). Tema 3. Sistemas basados en paso de mensajes..

◾ El maestro tiene asociada una colecci´n de filas de pixels.
o

◾ Cuando los procesos esclavos est´n ociosos esperan recibir una fila de pixels.
a

◾ Cuando no quedan m´s filas, el Maestro espera a que todos los procesos completen sus tareas
a
pendientes e informa de la finalizaci´n del c´lculo.
o
a

• Veremos una soluci´n que usa env´ as´
o
ıo ıncrono seguro y recepci´n s´
o ıncrona.

Procesos Maestro y Esclavo

§
process Maestro ;
begin
for i := 0 to num_esclavos-1 do
send( fila, Esclavo[i] ) ;
{ enviar trabajo a esclavo }
while queden filas sin colorear do
select
for j := 0 to ne − 1 when receive( colores, Esclavo[j] ) do
if quedan filas en la bolsa
then send( fila, Esclavo[j] )
else send( fin, Esclavo[j] );
visualiza(colores);
end
end
¦
§
process Esclavo[ i : 0..num_esclavos-1 ] ;
begin
receive( mensaje, Maestro );
while mensaje != fin do begin
colores := calcula_colores(mensaje.fila) ;
send (colores, Maestro );
receive( mensaje, Maestro );
end
end
¦

4.2.3

Iteraci´n s´
o ıncrona

Iteraci´n s´
o ıncrona

• Iteraci´n: En m´ltiples problemas num´ricos, un c´lculo se repite y cada vez se obtiene un resultado
o
u
e
a
que se utiliza en el siguiente c´lculo. El proceso se repite hasta obtener los resultados deseados.
a
• A menudo se pueden realizar los c´lculos de cada iteraci´n de forma concurrente.
a
o
• Paradigma de iteraci´n s´
o ıncrona:

◾ En un bucle diversos procesos comienzan juntos en el inicio de cada iteraci´n.
o

◾ La siguiente iteraci´n no puede comenzar hasta que todos los procesos hayan acabado la previa.
o
◾ Los procesos suelen intercambiar informaci´n en cada iteraci´n.
o
o

creado October 4, 2013- p´gina 113 / 222
a

¤

¥
¤

¥
SCD (13-14). Tema 3. Sistemas basados en paso de mensajes..
Ejemplo: Transformaci´n iterativa de un vector (1)
o

Supongamos que debemos realizar M iteraciones de un c´lculo que transforma un vector x de n reales:
a
xi−1 − xi + xi+1
,
2
(k)
(k)
x−1 = xn−1 ,
(k)

xi

(k+1)

=

(k)

(k)

i = 0, . . . , n − 1,

k = 0, 1, . . . , N,

x n = x0 .
(k)

(k)

Veremos una soluci´n que usa env´ as´
o
ıo ıncrono seguro y recepci´n s´
o ıncrona.
Ejemplo: Transformaci´n iterativa de un vector (2)
o

El esquema que se usar´ para implementar ser´ este:
a
a

• El n´mero de iteraciones es una constante predefinida m
u
• Se lanzan p procesos concurrentes.

• Cada proceso guarda una parte del vector completo, esa parte es un vector local con n/p entradas
reales, indexadas de 0 a n/p − 1 (vector bloque) (asumimos que n es m´ltiplo de p)
u
• Cada proceso, al inicio de cada iteraci´n, se comunica con sus dos vecinos las entradas primera y
o
ultima de su bloque.
´

• Al inicio de cada proceso, se leen los valores iniciales de un vector compartido que se llama valores
(con n entradas), al final se copian los resultados en dicho vector.
creado October 4, 2013- p´gina 114 / 222
a
SCD (13-14). Tema 3. Sistemas basados en paso de mensajes..
Ejemplo: Transformaci´n iterativa de un vector (3)
o
El c´digo de cada proceso puede quedar as´
o
ı:

§
process Tarea[ i : 0..p − 1 ] ;
var bloque : array[0..n/p-1] of float ; { bloque local (no compartido) }
begin
for j := 0 to n/p-1 do bloque[j] := valores[i*n/p+j] ; { lee valores }
for k := 0 to m do begin { bucle que ejecuta las iteraciones }
{ comunicacion de valores extremos con los vecinos }
send( bloque[0]
,Tarea[i-1 mod p] ); { enviar primero a anterior }
send( bloque[n/p-1],Tarea[i+1 mod p] ); { enviar ultimo a siguiente }
receive( izquierda, Tarea[i-1 mod p] ); { recibir ultimo de anterior }
receive( derecha,
Tarea[i+1 mod p] ); { recibir primero del siguiente }
{ calcular todas las entradas excepto la ultima }
for j := 0 to n/p-2 do begin
tmp := bloque[j] ;
bloque[j] := ( izquierda - bloque[j] + bloque[j+1] )/2;
izquierda := tmp ;
end
{ calcular ultima entrada }
bloque[n/p-1] := ( izquierda - bloque[n/p-1] + derecha )/2;
end
for j := 0 to n/p-1 do valores[i*n/p+j] := bloque[j] ; { escribre resultados }
end
¦

4.2.4

¤

¥

Encauzamiento (pipelining)

Encauzamiento (pipelining)

• El problema se divide en una serie de tareas que se han de completar una despu´s de otra
e
• Cada tarea se ejecuta por un proceso separado.

• Los procesos se organizan en un cauce (pipeline) donde cada proceso se corresponde con una etapa
del cauce y es responsable de una tarea particular.
• Cada etapa del cauce contribuir´ al problema global y devuelve informaci´n que es necesaria para
a
o
etapas posteriores del cauce.
• Patr´n de comunicaci´n muy simple ya que se establece un flujo de datos entre las tareas adyacentes
o
o
en el cauce.

Encauzamiento: Ejemplo (1)

Cauce paralelo para filtrar una lista de enteros

creado October 4, 2013- p´gina 115 / 222
a
SCD (13-14). Tema 3. Sistemas basados en paso de mensajes..

• Dada una serie de m primos p0 , p1 , ..., pm−1 y una lista de n enteros, a0 , a1 , a2 , ..., an−1 , encontrar
aquellos n´meros de la lista que son m´ltiplos de todos los m primos (n >> m)
u
u
• El proceso Etapa[i] (con i = 0, . . . , m − 1) mantiene el primo pi y chequea multiplicidad con pi .
• Veremos una soluci´n que usa operaciones s´
o
ıncronas.

Encauzamiento: Ejemplo (2)

§
{ vector (compartido) con la lista de primos }
var primos : array[0..m − 1] of float := { p0 , p1 , p2 , ⋯, pm−1 } ;

¤

{ procesos que ejecutan cada etapa: }

process Etapa[ i : 0..m − 1 ] ;
var izquierda : integer := 0 ;
begin
while izquierda >= 0 do begin
if i == 0 then
leer( izquierda ); { obtiene siguiente entero }
else
receive( izquierda, Etapa[i-1]);
if izquierda mod primos[i] == 0 then begin
if i != m-1 then
s_send ( izquierda, Etapa[i+1]);
else
imprime( izquierda );
end
end
end
¦

4.3

4.3.1

¥

Mecanismos de alto nivel en sistemas distribuidos
Introducci´n
o

Introducci´n
o

• Los mecanismos vistos hasta ahora (varios tipos de env´
ıo/recepci´n espera selectiva, ...) presentan un
o
bajo nivel de abstracci´n.
o

creado October 4, 2013- p´gina 116 / 222
a
SCD (13-14). Tema 3. Sistemas basados en paso de mensajes..

• Se ver´n dos mecanismos de mayor nivel de abstracci´n: Llamada a procedimiento remoto (RPC) e
a
o
Invocaci´n remota de m´todos (RMI).
o
e
• Est´n basados en la forma de comunicaci´n habitual en un programa: llamada a procedimiento.
a
o
◾ El llamador proporciona nombre del proc + par´metros, y espera.
a

◾ Cuando proc. termina, el llamador obtiene los resultados y contin´a.
u

• En el modelo de invocaci´n remota:
o

◾ El llamador invoca desde un proceso o m´quina diferente de donde se encuentra el procedimiento
a
invocado.
◾ El llamador se queda bloqueado hasta que recibe los resultados (esquema s´
ıncrono).
◾ El flujo de comunicaci´n es bidireccional (petici´n-respuesta).
o
o

4.3.2

◾ Se permite que varios procesos invoquen un procedimiento gestionado por otro proceso (esquema
muchos a uno).

El paradigma Cliente-Servidor

El paradigma Cliente-Servidor

• Paradigma m´s frecuente en programaci´n distribuida.
a
o

• Relaci´n asim´trica entre dos procesos: cliente y servidor.
o
e

◾ Proceso servidor: gestiona un recurso (por ejemplo, una base de datos) y ofrece un servicio a
otros procesos (clientes) para permitir que puedan acceder al recurso. Puede estar ejecut´ndose
a
durante un largo periodo de tiempo, pero no hace nada util mientras espera peticiones de los
´
clientes.

◾ Proceso cliente: necesita el servicio y env´ un mensaje de petici´n al servidor solicitando algo
ıa
o
asociado al servicio proporcionado por el servidor (p.e. una consulta sobre la base de datos).

El paradigma Cliente-Servidor

Es sencillo implementar esquemas de interacci´n cliente-servidor usando los mecanismos vistos. Para ello
o
usamos en el servidor un select que acepta peticiones de cada uno de los clientes:

creado October 4, 2013- p´gina 117 / 222
a
SCD (13-14). Tema 3. Sistemas basados en paso de mensajes..
§
process Cliente[ i : 0..n − 1 ] ;
begin
while true do begin
s_send( peticion, Servidor );
receive( respuesta, Servidor );
end
end

process Servidor ;
begin
while true do
select
for i:= 0 to n-1
when condicion[i] receive( peticion, Cliente[i] ) do
respuesta := servicio( peticion ) ;
s_send( respuesta, Cliente[i] ),
end
end
¦

¤

¥

Problemas de la soluci´n
o

No obstante, se plantean problemas de seguridad en esta soluci´n:
o

• Si el servidor falla, el cliente se queda esperando una respuesta que nunca llegar´.
a

• Si un cliente no invoca el receive(respuesta,Servidor) y el servidor realiza s_send(respuesta,Cliente[j]
s´
ıncrono, el servidor quedar´ bloqueado
a

Para resolver estos problemas:

• El par (recepci´n de petici´n, env´ de respuesta) se debe considerar como una unica operaci´n de
o
o
ıo
´
o
comunicaci´n bidireccional en el servidor y no como dos operaciones separadas.
o
• El mecanismo de llamada a procedimiento remoto (RPC) proporciona una soluci´n en esta l´
o
ınea.

4.3.3

Llamada a Procedimiento (RPC)

Introducci´n a RPC
o

• Llamada a procedimiento remoto (Remote Procedure Call): Mecanismo de comunicaci´n entre proo
cesos que sigue el esquema cliente-servidor y que permite realizar las comunicaciones como llamadas
a procedimientos convencionales (locales).

• Diferencia ppal respecto a una llamada a procedimiento local: El programa que invoca el procedimiento (cliente) y el procedimiento invocado (que corre en un proceso servidor) pueden pertenecer a
m´quinas diferentes del sistema distribuido.
a
creado October 4, 2013- p´gina 118 / 222
a
SCD (13-14). Tema 3. Sistemas basados en paso de mensajes..

Esquema de interacci´n en una RPC
o

• Representante o delegado (stub): procedimiento local que gestiona la comunicaci´n en el lado del
o
cliente o del servidor.
• Los procesos cliente y servidor no se comunican directamente, sino a trav´s de representantes.
e

Esquema general de una RPC. Inicio en el nodo cliente

1. En el nodo cliente se invoca un procedimiento remoto como si se tratara de una llamada a procedimiento
local. Esta llamada se traduce en una llamada al representante del cliente.

2. El representante del cliente empaqueta todos los datos de la llamada (nombre del procedimiento y
par´metros) usando un determinado formato para formar el cuerpo del mensaje a enviar (es muy usual
a
utilizar el proticolo XDR, eXternal Data Representation). Este proceso se suele denominar marshalling
o serializaci´n.
o

3. El representante el cliente env´ el mensaje con la petici´n de servicio al nodo servidor usando el
ıa
o
m´dulo de comunicaci´n del sistema operativo.
o
o
4. El programa del cliente se quedar´ bloqueado esperando la respuesta.
a

creado October 4, 2013- p´gina 119 / 222
a
SCD (13-14). Tema 3. Sistemas basados en paso de mensajes..

Esquema general de una RPC. Pasos en el nodo servidor y recepci´n de resultados en cliente
o

1. En el nodo servidor, el sistema operativo desbloquea al proceso servidor para que se haga cargo de la
petici´n y el mensaje es pasado al representante del servidor.
o

2. El representante del servidor desempaqueta (unmarshalling) los datos del mensaje de petici´n (ideno
tificaci´n del procedimiento y par´metros) y ejecuta una llamada al procedimiento local identificado
o
a
usando los par´metros obtenidos del mensaje.
a
3. Una vez finalizada la llamada, el representante del servidor empaqueta los resultados en un mensaje
y lo env´ al cliente.
ıa
4. El sistema operativo del nodo cliente desbloquea al proceso que hizo la llamada para recibir el resultado
que es pasado al representante del cliente.

5. El representante del cliente desempaqueta el mensaje y pasa los resultados al invocador del procedimiento.

Representaci´n de datos y paso de par´metros en la RPC
o
a
• Representaci´n de los datos
o

◾ En un sistema distribuido los nodos pueden tener diferente hardware y/o sistema operativo (sistema heterog´neo), utilizando diferentes formatos para representar los datos.
e
◾ En estos casos los mensajes se env´ usando una representaci´n intermedia y los representantes
ıan
o
de cliente y servidor se encargan de las conversiones necesarias.

• Paso de par´metros En RPC, los par´metros de la llamada se pueden pasar:
a
a

◾ por valor: en este caso basta con enviar al representante del servidor los datos aportados por el
cliente.

4.3.4

◾ por referencia: En este caso se pasa un puntero, por lo que se han de transferir tambi´n los
e
datos referenciados al servidor. Adem´s, en este caso, cuando el procedimiento remoto finaliza, el
a
representante del servidor debe enviar al cliente, junto con los resultados, los par´metros pasados
a
por referencia que han sido modificados.

Java Remote Method Invocation (RMI)

El modelo de objetos distribuidos

• Invocaci´n de m´todos en progr. orientada a objetos
o
e

◾ En programaci´n orientada a objetos, los objetos se comunican entre s´ mediante invocaci´n a
o
ı
o
m´todos.
e

◾ Para invocar el m´todo de un objeto hay que dar una referencia del objeto, el m´todo concreto y
e
e
los argumentos de la llamada.
◾ La interfaz de un objeto define sus m´todos, argumentos, tipos de valores devueltos y excepciones.
e

creado October 4, 2013- p´gina 120 / 222
a
SCD (13-14). Tema 3. Sistemas basados en paso de mensajes..
• Invocaci´n de m´todos remotos
o
e

◾ En un entorno distribuido, un objeto podr´ invocar m´todos de un objeto localizado en un nodo o
ıa
e
proceso diferente del sistema (objeto remoto) siguiendo el paradigma cliente-servidor como ocurre
en RPC.
◾ Un objeto remoto podr´ recibir invocaciones locales o remotas. Para invocar m´todos de un
ıa
e
objeto remoto, el objeto que invoca debe disponer de la referencia del objeto remoto del nodo
receptor, que es unica en el sistema distribuido.
´

El modelo de objetos distribuidos. Interfaz remota y representantes

• Interfaz remota: especifica los m´todos del objeto remoto que est´n accesibles para los dem´s objetos
e
a
a
as´ como las excepciones derivadas (p.e., que el servidor tarde mucho en responder).
ı

• Remote Method Invocation (RMI): acci´n de invocar un m´todo de la interfaz remota de un objeto
o
e
remoto. La invocaci´n de un m´todo en una interfaz remota sigue la misma sintaxis que un objeto local.
o
e

El modelo de objetos distribuidos. Interfaz remota y representantes
• El esquema de RMI es similar a la RPC:

◾ En el cliente: un representante local de la clase del objeto receptor (stub) implementa el marshalling y la comunicaci´n con el servidor, compartiendo la misma interfaz que el objeto receptor.
o
◾ En el servidor: la implementaci´n de la clase del objeto receptor (skeleton) recibe y traduce las
o
peticiones del stub, las env´ al objeto que implementa la interfaz remota y espera resultados
ıa
para formatearlos y envi´rselos al stub del cliente.
a

creado October 4, 2013- p´gina 121 / 222
a
SCD (13-14). Tema 3. Sistemas basados en paso de mensajes..

El modelo de objetos distribuidos. Referencias remotas

• Los stubs se generan a partir de la definici´n de la interfaz remota.
o

• Los objetos remotos residen en el nodo servidor y son gestionados por el mismo.
• Los procesos clientes manejan referencias remotas a esos objetos.

◾ Obtienen una referencia un´
ıvoca con la localizaci´n del objeto remoto dentro del sistema diso
tribuido (direcci´n IP, puerto de escucha e identificador).
o

• El contenido de la referencia remota no es directamente accesible, sino que es gestionado por el stub
y por el enlazador.

• Enlazador: servicio de un sistema distribuido que registra las asignaciones de nombres a referencias
remotas. Mantiene una tabla con pares (nombre, referencia remota).
◾ En el cliente, se usa para obtener la referencia de un objeto remoto a partir de su nombre
(lookup()).
◾ En el servidor, se usa para registrar o ligar (bind()) sus objetos remotos por nombre de forma
que los clientes pueden buscarlos.

Java RMI

• Mecanismo que ofrece Java (desde JDK 1.1) para invocar m´todos de objetos remotos en diferentes
e
JVMs.
• Permite que un programa Java exporte un objeto para que est´ disponible en la red, esperando conexe
iones desde objetos ejecut´ndose en otras m´quinas virtuales Java (JVM).
a
a
• La idea es permitir la programaci´n de aplicaciones distribuidas de forma integrada en Java como si
o
se tratara de aplicaciones locales, preservando la mayor parte de la sem´ntica de objetos en Java.
a

• Permite mantener seguro el entorno de la plataforma Java mediante gestores de seguridad y cargadores
de clases.
creado October 4, 2013- p´gina 122 / 222
a
SCD (13-14). Tema 3. Sistemas basados en paso de mensajes..
Particularidades de Java RMI

• Las interfaces remotas se definen como cualquier interfaz Java pero deben extender una interfaz
denominada Remote y lanzar excepciones remotas para actuar como tales.

• En una llamada remota, los par´metros de un m´todo son todos de entrada y la salida es el resultado
a
e
de la llamada.
◾ Los par´metros que son objetos remotos se pasan por referencia.
a

◾ Los par´metros que son objetos locales (argumentos no remotos) y los resultados se pasan por
a
valor (las referencias solo tienen sentido dentro de la misma JVM).
◾ Cuando el servidor no tiene la implementaci´n de un objeto local, la JVM se encarga de descargar
o
la clase asociada a dicho objeto.

• En Java RMI, el enlazador se denomina rmiregistry.

Arquitectura de Java RMI

• Generalmente las aplicaciones RMI constan de servidor y clientes.

• El sistema RMI proporciona los mecanismos para que el servidor y los clientes se comuniquen e
intercambien informaci´n.
o

Arquitectura de Java RMI. Nivel de aplicaci´n
o

Nivel de Aplicaci´n: Los clientes y el servidor implementan la funcionalidad de la aplicaci´n RMI:
o
o
• Servidor:

◾ Crea objetos remotos.

creado October 4, 2013- p´gina 123 / 222
a
SCD (13-14). Tema 3. Sistemas basados en paso de mensajes..

◾ Hace accesible las referencias a dichos objetos remotos. Para ello, se registran los objetos remotos
en el rmiregistry.
◾ Se mantiene activo esperando la invocaci´n de m˜etodos sobre dichos objetos remotos por parte
o
n
de los clientes.

• Clientes:

◾ Deben declarar objetos de la interfaz remota.

◾ Deben obtener referencias a objetos remotos (stubs) en el servidor.
◾ Invocan los m´todos remotos (usando el stub).
e

Este tipo de aplicaciones se suelen denominar Aplicaciones de objetos distribuidos

Arquitectura de Java RMI. Nivel de aplicaci´n(2)
o

Las aplicaciones de objetos distribuidos requieren:
• Localizar objetos remotos:

◾ Para ello, las aplicaciones pueden registrar sus objetos remotos utilizando el servicio rmiregistry,
o puede enviar y devolver referencias a objetos remotos como argumentos y resultados.

• Comunicarse con objetos remotos:

• Cargar bytecodes de objetos que se pasan como par´metros o valores de retorno.
a

Arquitectura de Java RMI. Sistema RMI
• Nivel de stubs

◾ El papel del Skeleton lo hace la plataforma RMI (a partir de JDK 1.2).

◾ El stub se genera autom´ticamente bajo demanda en tiempo de ejecuci´n (a partir de JDK 1.5,
a
o
antes se usaba un compilador).
◾ El stub tiene la misma interfaz que el objeto remoto y conoce su localizaci´n. Realiza todo el
o
marshalling necesario para la llamada remota.

creado October 4, 2013- p´gina 124 / 222
a
SCD (13-14). Tema 3. Sistemas basados en paso de mensajes..

◾ Debe haber un stub por cada instancia de una interfaz remota.

• Nivel de referencias: Se encarga de:

◾ Interpretar las referencias remotas que manejan los stubs para permitirles acceder a los m´todos
e
correspondientes de los objetos remotos

◾ Enviar y recibir los paquetes (resultantes del marshalling de las peticiones/respuestas) usando
los servicios del nivel de transporte.

• Nivel de transporte: Se encarga de conectar las diferentes JVMs en el sistema distribuido. Se basa
en el protocolo de red TCP/IP.

Pasos para implementar una aplicaci´n Java RMI
o

Suponiendo, por simplicidad, que el cliente usa un unico objeto remoto, los pasos ser´
´
ıan:
1. Crear la interfaz remota

2. Implementar el objeto remoto

3. Implementar los programas clientes

1. Crear la Interfaz remota

• La interfaz remota declara los m´todos que pueden invocar remotamente los clientes.
e
• Deben extender la interfaz Remote del paquete java.rmi.

• Los m´todos definidos deben poder lanzar una excepci´n remota.
e
o

Ejemplo: Interfaz de un contador remoto Contador I.java

§
import java.rmi.Remote;
import java.rmi.RemoteException;
public interface Contador_I extends Remote {
public void incrementa(int valor) throws RemoteException;
public int getvalor() throws RemoteException;
}
¦

2. Implementar el objeto remoto

• Inicialmente se deben de definir los m´todos de la interfaz remota:
e

Ejemplo: Clase para contador remoto Contador.java

creado October 4, 2013- p´gina 125 / 222
a

¤

¥
SCD (13-14). Tema 3. Sistemas basados en paso de mensajes..

§
import java.rmi.*;
import java.rmi.server.*;

¤

public class Contador implements Contador_I{
private int valor;
public Contador() throws RemoteException {
valor=0;
}
public void incrementa(int valor) throws RemoteException {
this.valor+=valor;
}
public int getvalor() throws RemoteException {
return valor;
}
...}
¦

¥

2. Implementar el objeto remoto(2)

Una vez definidos los m´todos de la interfaz, se debe crear el objeto remoto que implementa la interfaz
e
remota y exportarlo al entorno RMI para habilitar la recepci´n de invocaciones remotas. Eso implica:
o
1. Crear e instalar un gestor de seguridad (security manager).
2. Crear y exportar el objeto remoto.

3. Se ha de registrar la referencia a dicho objeto remoto (el stub) en el servidor de nombre (rmiregistry)
asoci´ndole un nombre. Esto se hace con rebind(nombre, referencia).
a

Estos pasos se podr´ incluir en el programa ppal de la clase que implementa la interfaz remota (como en
ıan
el siguiente ejemplo) o en cualquier otro m´todo de otra clase.
e
2. Implementar el objeto remoto(3)

Ejemplo: m´todo main para contador remoto Contador.java
e

§
...

public static void main(String[] args) {
// Instalacion del gestor de seguridad
if (System.getSecurityManager() == null) {
System.setSecurityManager(new SecurityManager());
}
try {
String nombre = "contador";
Creacion de una instancia de la clase
Contador_I cont = new Contador();
La exportamos y le damos nombre en el RMI registry

creado October 4, 2013- p´gina 126 / 222
a

¤
SCD (13-14). Tema 3. Sistemas basados en paso de mensajes..

Contador_I stub =(Contador_I)
UnicastRemoteObject.exportObject(cont, 0);
Registry registry = LocateRegistry.getRegistry();
registry.rebind(nombre,stub);
System.out.println("Contador ligado");
} catch (Exception e) {
System.err.println("Contador exception:");
e.printStackTrace();
}

¦

}

¥

3. Implementar los programas clientes
Implementar los programas clientes

• El cliente tambi´n debe instalar un gestor de seguridad para que el stub local pueda descargar la
e
definici´n de una clase desde el servidor.
o

• El programa cliente deber´ obtener la referencia del objeto remoto, consultando el servicio de enlazador,
a
rmiregistry, en la m´quina del servidor, usando lookup(...).
a

• Una vez obtenida la referencia remota, el programa interact´a con el objeto remoto invocando m´todos
u
e
del stub usando los argumentos adecuados (como si fuera local).

3. Implementar los programas clientes (2)

Ejemplo: Programa cliente del contador remoto Cliente.java

§
import java.rmi.*;

¤

public class Cliente {
public static void main(String args[]) {
if (System.getSecurityManager() == null) {
System.setSecurityManager(new SecurityManager());
}
try {
// Obteniendo una referencia a RMI registry en nodo servidor
// El primer argumento del programa debe ser el nodo servidor
Registry registry = LocateRegistry.getRegistry(args[0]);
//Se invoca lookup en el registry para buscar objeto remoto
// mediante el nombre usado en la clase Contador
Contador_I cont = (Contador_I)(registry.lookup("contador");
cont.incrementa(2);
System.out.println("VALOR="+cont.getvalor());
} catch (Exception e) {
System.err.println("Contador_I exception:");
e.printStackTrace();
}
}
}
¦

creado October 4, 2013- p´gina 127 / 222
a

¥
SCD (13-14). Tema 3. Sistemas basados en paso de mensajes..
Bibliograf´ del tema 3.
ıa

Para m´s informaci´n, ejercicios, bibliograf´ adicional, se puede consultar:
a
o
ıa

3.1. Mecanismos b´sicos en sistemas basados en paso de mensajes. Palma (2003), cap´
a
ıtulos 7,8,9.
Almeida (2008), cap´
ıtulo 3. Kumar (2003), cap´
ıtulo 6.

3.2. Paradigmas de interacci´n de procesos en programas distribuidos Andrews (2000), cap´
o
ıtulo 9. Almeida
(2008), cap´
ıtulos 5,6.
3.3. Mecanismos de alto nivel en sistemas distribuidos. RPC y RMI. Palma (2003), cap´
ıtulo 10. Coulouris
(2011), cap´
ıtulo 5.

4.4

32

Problemas del tema 3.

En un sistema distribuido, 6 procesos clientes necesitan sincronizarse de forma espec´
ıfica para realizar
cierta tarea, de forma que dicha tarea s´lo podr´ ser realizada cuando tres procesos est´n preparados para
o
a
e
realizarla. Para ello, env´ peticiones a un proceso controlador del recurso y esperan respuesta para poder
ıan
realizar la tarea espec´
ıfica. El proceso controlador se encarga de asegurar la sincronizaci´n adecuada. Para
o
ello, recibe y cuenta las peticiones que le llegan de los procesos, las dos primeras no son respondidas y
producen la suspensi´n del proceso que env´ la petici´n (debido a que se bloquea esperando respuesta)
o
ıa
o
pero la tercera petici´n produce el desbloqueo de los tres procesos pendientes de respuesta. A continuaci´n,
o
o
una vez desbloqueados los tres procesos que han pedido (al recibir respuesta), inicializa la cuenta y procede
c´
ıclicamente de la misma forma sobre otras peticiones.
El c´digo de los procesos clientes es el siguiente, asumiendo que se usan operaciones s´
o
ıncronas.

§
process Cliente[ i : 0..5 ] ;
begin
while true do begin
send( peticion, Controlador );
receive( permiso, Controlador );
Realiza_tarea_grupal( );
end
end
¦

¤§
process Controlador ;
begin
while true do begin
...
end
end
¥¦

¥

Describir en pseudoc´digo el comportamiento del proceso controlador, utilizando una orden de espera seleco
tiva que permita implementar la sincronizaci´n requerida entre los procesos. Es posible utilizar una sentencia
o
del tipo select for i=... to ... para especificar diferentes ramas de una sentencia selectiva que
comparten el mismo c´digo dependiente del valor de un ´
o
ındice i.

33

¤

En un sistema distribuido, 3 procesos productores producen continuamente valores enteros y los env´ a un
ıan

creado October 4, 2013- p´gina 128 / 222
a
SCD (13-14). Tema 3. Sistemas basados en paso de mensajes..

proceso buffer que los almacena temporalmente en un array local de 4 celdas enteras para ir envi´ndoselos
a
a un proceso consumidor. A su vez, el proceso buffer realiza lo siguiente, sirviendo de forma equitativa al
resto de procesos:

a) Env´ enteros al proceso consumidor siempre que su array local tenga al menos dos elementos
ıa
disponibles.

b) Acepta env´ de los productores mientras el array no est´ lleno, pero no acepta que cualquier productor
ıos
e
pueda escribir dos veces consecutivas en el b´fer.
u

El c´digo de los procesos productor y consumidor es el siguiente, asumiendo que se usan operaciones
o
s´
ıncronas.

§
{ Proceso Productor(i ), i=0,1,2 }

while true do begin
Produce(&dato );
send( &dato, Buffer );
end
¦

¤
§
{ Proceso Consumidor }

while true do begin
receive ( &dato, Buffer );
Consume (dato);
end
¥
¦

Describir en pseudoc´digo el comportamiento del proceso Buffer, utilizando una orden de espera selectiva
o
que permita implementar la sincronizaci´n requerida entre los procesos.
o

§
{ Proceso Buffer }

while true do begin
...
end
¦

¤

¥

¤

¥

34

Suponer un proceso productor y 3 procesos consumidores que comparten un buffer acotado de tama˜o B.
n
Cada elemento depositado por el proceso productor debe ser retirado por todos los 3 procesos consumidores
para ser eliminado del buffer. Cada consumidor retirar´ los datos del buffer en el mismo orden en el que son
a
depositados, aunque los diferentes consumidores pueden ir retirando los elementos a ritmo diferente unos de
otros. Por ejemplo, mientras un consumidor ha retirado los elementos 1, 2 y 3, otro consumidor puede haber
retirado solamente el elemento 1. De esta forma, el consumidor m´s r´pido podr´ retirar hasta B elementos
a a
ıa
m´s que el consumidor m´s lento.
a
a
Describir en pseudoc´digo el comportamiento de un proceso que implemente el buffer de acuerdo con el
o
esquema de interacci´n descrito usando una construcci´n de espera selectiva, as´ como el del proceso
o
o
ı
productor y de los procesos consumidores. Comenzar identificando qu´ informaci´n es necesario representar,
e
o
para despu´s resolver las cuestiones de sincronizaci´n. Una posible implementaci´n del bufffer mantendr´
e
o
o
ıa,
para cada proceso consumidor, el puntero de salida y el n´mero de elementos que quedan en el buffer por
u
consumir (ver figura).

creado October 4, 2013- p´gina 129 / 222
a
SCD (13-14). Tema 3. Sistemas basados en paso de mensajes..

35

Una tribu de antrop´fagos comparte una olla en la que caben M misioneros. Cuando alg´n salvaje quiere
o
u
comer, se sirve directamente de la olla, a no ser que ´sta est´ vac´ Si la olla est´ vac´ el salvaje despertar´
e
e
ıa.
a
ıa,
a
al cocinero y esperar´ a que ´ste haya rellenado la olla con otros M misioneros.
a
e
Proceso Salvaje(i), i=0,1,2 :

§
while true do begin
Servirse_1_misionero();
Comer();
end
¦

Proceso Cocinero :

¤
§
while true do begin
Dormir();
Rellenar_Olla();
end
¥
¦

¤

¥

Implementar los procesos salvajes y cocinero usando paso de mensajes, usando un proceso olla que incluye
una construcci´n de espera selectiva que sirve peticiones de los salvajes y el cocinero para mantener la
o
sincronizaci´n requerida, teniendo en cuenta que:
o
• La soluci´n no debe producir interbloqueo.
o

• Los salvajes podr´n comer siempre que haya comida en la olla,
a
• Solamente se despertar´ al cocinero cuando la olla est´ vac´
a
e
ıa.
• Lois procesos usan operaciones de comunicaci´n s´
o ıncronas.

36

Considerar un conjunto de N procesos, P(i), i = 0, ..., N − 1 conectados en forma de anillo. Cada proceso
tiene un valor local almacenado en su variable local mi valor. Deseamos calcular la suma de los valores
locales almacenados por los procesos de acuerdo con el algoritmo que se expone a continuaci´n.
o

creado October 4, 2013- p´gina 130 / 222
a
SCD (13-14). Tema 3. Sistemas basados en paso de mensajes..

Los procesos realizan una serie de iteraciones para hacer circular sus valores locales por el anillo. En la
primera iteraci´n, cada proceso env´ su valor local al siguiente proceso del anillo, al mismo tiempo que
o
ıa
recibe del proceso anterior el valor local de ´ste. A continuaci´n acumula la suma de su valor local y el
e
o
recibido desde el proceso anterior. En las siguientes iteraciones, cada proceso env´ al siguiente proceso
ıa
siguiente el valor recibido en la anterior iteraci´n, al mismo tiempo que recibe del proceso anterior un nuevo
o
valor. Despu´s acumula la suma. Tras un total de N − 1 iteraciones, cada proceso conocer´ la suma de todos
e
a
los valores locales de los procesos.
Dar una descripci´n en pseudoc´digo de los procesos siguiendo un estilo SPMD y usando operaciones de
o
o
env´ y recepci´n s´
ıo
o ıncronas.

§
{ Proceso P[i ], i =0,..., N−1 }

var mi_valor : integer := ... ;
suma
: integer ;
begin
for j := 0 hasta N-1 do begin
...
end
end
¦

¤

¥

37

Considerar un estanco en el que hay tres fumadores y un estanquero. Cada fumador continuamente l´ un
ıa
cigarro y se lo fuma. Para liar un cigarro, el fumador necesita tres ingredientes: tabaco, papel y cerillas.
Uno de los fumadores tiene solamente papel, otro tiene solamente tabaco, y el otro tiene solamente cerillas.
El estanquero tiene una cantidad infinita de los tres ingredientes.
creado October 4, 2013- p´gina 131 / 222
a
SCD (13-14). Tema 4. Introducci´n a los sistemas de tiempo real..
o

• El estanquero coloca aleatoriamente dos ingredientes diferentes de los tres que se necesitan para hacer
un cigarro, desbloquea al fumador que tiene el tercer ingrediente y despu´s se bloquea. El fumador
e
seleccionado, se puede obtener f´cilmente mediante una funci´n int Genera ingrediente() que
a
o
devuelve el ´
ındice (0,1, ´ 2) del fumador escogido.
o
• El fumador desbloqueado toma los dos ingredientes del mostrador, desbloqueando al estanquero, l´
ıa
un cigarro y fuma durante un tiempo.

• El estanquero, una vez desbloqueado, vuelve a poner dos ingredientes aleatorios en el mostrador, y se
repite el ciclo.

Describir una soluci´n distribuida que use env´ as´
o
ıo ıncrono seguro y recepci´n s´
o ıncrona, para este problema
usando un proceso Estanquero y tres procesos fumadores (Fumador(i), i=0,1,2).
Proceso Estanquero :

§
while true do begin
....
end
¦

Proceso Fumador(i), i=0,1,2 :

¤
§
while true do begin
....
end
¥
¦

¤

¥

creado October 4, 2013- p´gina 132 / 222
a
Chapter 5

Tema 4. Introducci´n a los sistemas de
o
tiempo real.
5.1

5.1.1

Concepto de sistema de tiempo real. Medidas de tiempo y modelo de
tareas.
Definici´n, tipos y ejemplos
o

Sistemas de Tiempo Real

• Constituyen un tipo de sistema en el que la ejecuci´n del sistema se debe producir dentro de unos
o
plazos de tiempo predefinidos para que funcione con la suficiente garant´
ıa.

• En un sistema adem´s concurrente ser´ necesario que todos los procesos sobre un procesador o sobre
a
a
varios se ejecuten en los plazos de tiempo predefinidos.

Definici´n de un Sistema de Tiempo Real
o

Stankovic (1997) da la siguiente definici´n:
o
Un sistema de tiempo real es aquel sistema cuyo funcionamiento correcto depende no s´lo
o
de resultados l´gicos producidos por el mismo, sino tambi´n del instante de tiempo en el que
o
e
se producen esos resultados

Correcci´n Funcional + Correcci´n Temporal
o
o

El no cumplimiento de una restricci´n temporal lleva a un fallo del sistema
o
133
SCD (13-14). Tema 4. Introducci´n a los sistemas de tiempo real..
o
Ejemplo: Sistema de Control

• Objetivo: Ejecutar el lazo de control del sistema en instantes de tiempo prefijados.

• Condici´n de tiempo real: no puede haber retrasos en la ejecuci´n del lazo de control, ya que afecta
o
o
al rendimiento y provoca perdida de estabilidad.
Consignas

SISTEMA
DE
CONTROL
Medidas

Visualización
datos

Acciones

SISTEMA
CONTROLADO
ENTORNO FÍSICO

Los sistemas de control (no necesariamente computadores sino sistemas el´ctricos, mec´nicos, ´pticos) suelen
e
a
o
realizar la acci´n de correcci´n para el control del sistema en un lazo (bucle) con el objeto de mantener
o
o
o establecer una condiciones en el sistema controlado. En la actualidad los sistemas de control se est´n
a
“digitalizando”, es decir, sustituyendo por sistemas de control computerizados.
La estructura general de una aplicaci´n de control incluye:
o

• Sistema de control: que se encarga de monitorizar el sistema controlado, y si se produce una desviaci´n
o
respecto del comportamiento esperado se activan las se˜ales de control (acciones) especificas para
n
disminuir esa desviaci´n.
o
• Sensores: dispositivos de naturaleza electr´magn´tica, mec´nica u ´ptica que obtienen el estado del
o
e
a
o
entorno f´
ısico a partir de la cuantificaci´n de alguna variable f´
o
ısica. Los sensores se encargan de
realizar la transducci´n entre valores en alguna variable f´
o
ısica y la valores de tensi´n (los que se
o
utilizan desde cualquier medio computerizado).
Ejemplos: sensores de temperatura, sensores de presencia, de luminosidad, tac´metros, . . .
o

• Actuadores: dispositivos de naturaleza electromagn´tica, mec´nica u ´ptica que realizan acciones
e
a
o
concretas en el entorno f´
ısico a partir de las se˜ales de control enviadas por el sistema de control. La
n
traducci´n pasa valores de tensi´n en acciones concretas.
o
o
Ejemplos: motores, lamparas, valvulas, . . .

• Sistema Controlado: es el sistema f´
ısico del que queremos controlar su comportamiento.

• Consignas: son las ordenes que realizan los usuarios para establecer el sistema controlado en un valor
de referencia.

creado October 4, 2013- p´gina 134 / 222
a
SCD (13-14). Tema 4. Introducci´n a los sistemas de tiempo real..
o

• Visualizaci´n de datos: se obtienen los datos para que el operador pueda visualizarlos.
o

¿Qu´ tipo de sistema de tiempo real es un sistema de control? Depende del tipo de actividad, pero para
e
actividades de control deber´ ser de tipo estricto.
ıa
Tipos de Sistemas de Tiempo Real

Habitualmente suele asociarse la denominaci´n de sistemas de tiempo real a los siguientes tipos de sistemas:
o

• Sistema “en-l´
ınea”: Siempre est´ disponible, pero no se garantiza una respuesta en intervalo de
a
tiempo acotado.
◾ Ejemplos: Cajeros autom´ticos, sistemas de reservas de vuelo.
a

• Sistema interactivo: El sistema ofrece una respuesta en un tiempo, aunque no importa el tiempo que
necesita para su ejecuci´n.
o
◾ Ejemplos: Reproductor DVD, sistema aire acondicionado, juegos, ..

• Sistema de respuesta r´pida: El sistema ofrece una respuesta en el menor tiempo posible y de forma
a
inmediata.
◾ Ejemplos: Sistema anti incendios, alarmas, etc.

Tipos de Sistemas de Tiempo Real

Sistema de
respuesta
rápida

Sistema
En-línea
STR

Sistema
interactivo

creado October 4, 2013- p´gina 135 / 222
a
SCD (13-14). Tema 4. Introducci´n a los sistemas de tiempo real..
o
Ejemplos de Sistemas de Tiempo Real

En la actualidad hay muchos ejemplos de uso de Sistemas de Tiempo Real, podemos citar algunos de ellos:

• Automoci´n: sistema de ignici´n, transmisi´n, direcci´n asistida, frenos antibloqueo (ABS), control de
o
o
o
o
la tracci´n, ...
o

• Electrodom´sticos: televisores, lavadoras, hornos de microondas, reproductores de videos o DVDs,
e
sistemas de seguridad y vigilancia, ...
• Aplicaciones aeroespaciales: control de vuelos, controladores de motores, pilotos autom´ticos, ...
a
• Equipamiento m´dico: como sistemas de monitorizaci´n de anestesia, monitores ECG,
e
o

• Sistemas de defensa: como sistemas radar de aviones, sistemas de radio, control de misiles, ...

5.1.2

Propiedades de los Sistemas de Tiempo Real

Propiedades de un STR

Al depender la correcci´n del sistema de las restricciones temporales, los sistemas de tiempo real tienen que
o
cumplir una serie de propiedades:
• Reactividad.

• Predecibilidad.
• Confiabilidad.

a continuaci´n veremos cada una de estas propiedades con m´s detalle.
o
a
Propiedad: Reactividad

El sistema tiene que interaccionar con el entorno, y responder de la manera esperada a los
est´
ımulos externos dentro de un intervalo de tiempo previamente definido.

creado October 4, 2013- p´gina 136 / 222
a
SCD (13-14). Tema 4. Introducci´n a los sistemas de tiempo real..
o

Propiedad: Predecibilidad

Tener un comportamiento predecible implica que la ejecuci´n del sistema tiene que ser determinista, y por
o
lo tanto, se debe garantizar su ejecuci´n dentro del plazo de tiempo definido.
o

• Las respuestas han de producirse dentro de las restricciones temporales impuestas por el entorno
(sistema controlado), y que suele ser diferente para cada proceso del sistema.

• Es necesario conocer el comportamiento temporal de los componentes software (SO, middleware, librer´ etc) y hardware utilizados, as´ como del lenguaje de programaci´n.
ıa,
ı
o
• Si no se puede tener un conocimiento temporal exacto, hay que definir marcos de tiempo acotados; p.e.
conocer el tiempo de peor ejecuci´n de un algoritmo, el tiempo m´ximo de acceso a un dato de E/S)
o
a

Propiedad: Confiabilidad

• La Confiabilidad (Dependability) mide el grado de confianza que se tiene del sistema. Depende de:
◾ Disponibilidad (avalaibility). Capacidad de proporcionar servicios siempre que se solicita.

◾ Robustez o tolerancia a fallos (fault tolerant). Capacidad de operar en situaciones excepcionales
sin poseer un comportamiento catastr´fico.
o

◾ Fiabilidad (reliability). Capacidad de ofrecer siempre los mismos resultados bajo las mismas
condiciones.
◾ Seguridad: Capacidad de protegerse ante ataques o fallos accidentales o deliberados (safety), y
a la no vulnerabilidad de los datos (security).

• Cuando esta propiedad es cr´
ıtica (su no cumplimiento lleva a p´rdida humana o econ´mica), el sistema
e
o
se denomina sistema de tiempo real cr´
ıtico (safety-critical system)
◾ Ejemplos: Sistemas de Avi´nica, Sistemas de automoci´n, Centrales nucleares, etc.
o
o

creado October 4, 2013- p´gina 137 / 222
a
SCD (13-14). Tema 4. Introducci´n a los sistemas de tiempo real..
o
Tipos de STRs (otra clasif. distinta)
Tipo
No permisivos o estrictos (hard)
Permisivos, flexibles
o no estrictos (soft)
Firmes

Caracter´
ısticas
Plazo de respuesta dentro del l´
ımite
preestablecido.

Aunque el plazo de respuesta es importante, el sistema funciona correctamente aunque no respondan en
el plazo de tiempo fijado
Se permiten algunos fallos en el
plazo de respuesta, pero un n´mero
u
excesivo provoca una fallo completo
del sistema

Ejemplos
Control de vuelo de una aeronave.
Sistema autom´tico de frenado
a
ABS.
Sistema de adquisici´n de datos
o
meteorol´gicos.
o
Sistema de control de reserva de
vuelos.
Sistema de video bajo demanda.

Los sistemas de tiempo real pueden tener componentes de las tres clases.

Imagen obtenida de:

http://www.embedded.com/electronics-blogs/beginner-s-corner/4023859/Introduction-to-Real-Time

5.1.3

Modelo de Tareas

Modelo de Tareas

• Un sistema de tiempo real se estructura en tareas que acceden a los recursos del sistema.

creado October 4, 2013- p´gina 138 / 222
a
SCD (13-14). Tema 4. Introducci´n a los sistemas de tiempo real..
o

Tarea 1

Tarea 2

Tarea 3

Tarea 4

codigo

codigo

codigo

codigo

restricciones
temporales

restricciones
temporales

restricciones
temporales

restricciones
temporales

Memoria

CPU

Recurso 1

Recurso 2

Recurso 3

Tareas y recursos. Definici´n.
o

En los STR cabe distinguir estos dos tipos de elementos:

• Tarea: El conjunto de acciones que describe el comportamiento del sistema o parte de ´l en base a la
e
ejecuci´n secuencial de una secci´n de c´digo (o programa). Equivalente al proceso o hebra.
o
o
o
◾ La tarea satisface una necesidad funcional concreta.

◾ La tarea tiene definida unas restricciones temporales a partir de los Atributos Temporales.

• Recursos: Elementos disponibles para la ejecuci´n de las tareas.
o
◾ Recursos Activos: Procesador, Red, ...

◾ Recursos Pasivos: Datos, Memoria, Dispositivos de E/S, ...

Atributos temporales

• Tiempo de computo o de ejecuci´n (C): Tiempo necesario para la ejecuci´n de la tarea.
o
o

• Tiempo de respuesta (R): Tiempo que ha necesitado el proceso para completarse totalmente.
• Plazo de respuesta m´xima (deadline) (D): Define el m´ximo tiempo de respuesta posible.
a
a

• Periodo (T): Intervalo de tiempo entre dos activaciones sucesivas en el caso de una tarea peri´dica.
o
creado October 4, 2013- p´gina 139 / 222
a
SCD (13-14). Tema 4. Introducci´n a los sistemas de tiempo real..
o

Activación i

Activación (i+1)

Tiempo de computo ( C)
C = C1 + C2

Tiempo de respuesta (R)
Plazo de respuesta máxima (D)
Periodo (T)

Tipos de Tareas

• Peri´dica: T es el per´
o
ıodo de activaci´n de la tarea.
o
T

T

T

t
D

D

D

fallo
• Aperi´dica:
o
t
D

D

• Espor´dica: T es la separaci´n m´
a
o
ınima entre eventos.
T

T
t

D

D

creado October 4, 2013- p´gina 140 / 222
a
SCD (13-14). Tema 4. Introducci´n a los sistemas de tiempo real..
o
Planificaci´n de Tareas
o

• La planificaci´n de tareas consiste en asignar las tareas a los recursos activos de un sistema (princio
palmente el procesador o procesadores) para garantizar la ejecuci´n de todas las tareas de acuerdo a
o
un conjunto de restricciones especificas.
◾ En tareas de tiempo real las restricciones suelen estar asociadas a restricciones temporales como
los plazos l´
ımites.
Tarea 1

Tarea 2

Tarea 3

Tarea 4

CORE 1

t
CORE 2

t

Dise˜o de la planificaci´n de tareas.
n
o

El problema de la planificaci´n supone:
o

• Determinar los procesadores disponibles a los que se puede asociar las tareas.
• Determinar las relaciones de dependencias de las tareas:

◾ Relaciones de precedencia que hay entre las distintas tareas.

◾ Determinar los recursos comunes a los que acceden las distintas tareas.

• Determinar el orden de ejecuci´n de la tareas para garantizar las restricciones especificadas.
o

Esquema de planificaci´n de tareas
o

Para determinar la planificabilidad de un conjunto de tareas se requiere un esquema de planificaci´n que
o
cubra los dos siguientes aspectos:

• Un algoritmo de planificaci´n, que define un criterio (pol´
o
ıtica de planificaci´n) que determina el orden
o
de acceso de las tareas a los distintos procesadores.
• Un m´todo de an´lisis (test de planificabilidad) que permite predecir el comportamiento temporal del
e
a
sistema, y determina si la planificabilidad es factible bajo las condiciones o restricciones especificadas

creado October 4, 2013- p´gina 141 / 222
a
SCD (13-14). Tema 4. Introducci´n a los sistemas de tiempo real..
o

◾ Se pueden comprobar si los requisitos temporales est´n garantizados en todos los casos posibles.
a

◾ En general se estudia el peor comportamiento posible, es decir, con el WCET (Worst Case
Execution Time).
C´lculo del WCET.
a

• Todos los m´todos de planificaci´n parte de que se conoce el WCET (C), el tiempo de peor ejecuci´n
e
o
o
de cada tarea.

• ¿ C´mo podemos calcular el valor de C para cada tarea ?
o

• Hay dos formas de obtenerlo:

◾ Medida directa del tiempo de ejecuci´n (en el peor caso) en la plataforma de ejecuci´n.
o
o
▸ Se realizan m´ltiples experimentos, y se hace una estad´
u
ıstica.

◾ An´lisis del c´digo ejecutable
a
o

▸ Se descompone el c´digo en un grafo de bloques secuenciales.
o
▸ Se calcula el tiempo de ejecuci´n de cada bloque.
o
▸ Se busca el camino m´s largo.
a

Restricciones temporales

Para determinar la planificaci´n del sistema necesitamos conocer las restricciones temporales de cada tarea
o
del sistema.
Aqu´ vemos dos ejemplos de restricciones temporales:
ı

• C = 2 ms, T = D = 10 ms. Es una tarea peri´dica que se activa cada 10 ms, y se ejecuta en un tiempo
o
m´ximo de 2 ms en el peor de los casos.
a

• C = 10 ms, T = 100 ms; D = 90 ms. Es una tarea peri´dica que se activa cada 100 ms, se ejecuta en
o
cada activaci´n un m´ximo de 10 ms, y desde que se inicia la activaci´n hasta que concluye no puede
o
a
o
pasar m´s de 90 ms.
a

5.2

Esquemas de planificaci´n
o

Tipos de Esquemas de Planificaci´n
o

Los esquemas de planificaci´n para un sistema monoprocesador son:
o
• Planificaci´n est´tica off-line sin prioridades
o
a
◾ Planificaci´n c´
o ıclica (ejecutivo c´
ıclico)

• Planificaci´n basada en prioridades
o
◾ Prioridades est´ticas
a

▸ Prioridad al m´s frecuente (RMS, Rate Monotonic Scheduling)
a

creado October 4, 2013- p´gina 142 / 222
a
SCD (13-14). Tema 4. Introducci´n a los sistemas de tiempo real..
o

▸ Prioridad al m´s urgente (DMS, Deadline Monotonic Scheduling)
a

◾ Prioridades din´micas
a

5.2.1

▸ Proximidad del plazo de respuesta (EDF, Earliest Deadline First)
▸ Prioridad al de menor holgura (LLF, Least Laxity First)

Planificaci´n C´
o
ıclica.

Planificaci´n C´
o
ıclica

• La planificaci´n se basa en construir un plan de ejecuci´n (plan principal) de forma explicita y fuera
o
o
de l´
ınea (off-line) en el que se especifica el entrelazado de las tareas peri´dicas de tal forma que su
o
ejecuci´n c´
o ıclica garantiza el cumplimiento de los plazos de las tareas.
◾ La estructura de control o programa c´
ıclico se denomina ejecutivo c´
ıclico.

• El entrelazado es fijo y se define en el plan principal que se construye antes de poner en marcha el
sistema (off-line).

• La duraci´n del ciclo principal es igual al hiperperiodo
o
◾ TM = mcm(T1 , T2 , . . . , Tn )

◾ se supone tiempo entero (ticks de reloj)

◾ el comportamiento temporal del sistema se repite cada ciclo principal

Ejemplo de planificaci´n c´
o ıclica.
Tarea
A
B
C
D
E

T
25
25
50
50
100

C
10
8
5
4
2

• El ciclo principal dura 100 ms

TM = mcm(25, 25, 50, 50, 100) = 100

• Se compone de 4 ciclos secundarios de 25 ms cada uno.

TM = 100 ms

TS = 25 ms

A
0

B

C

A
25

B

D

E

A
50

B

C

A
75

B

D
100

creado October 4, 2013- p´gina 143 / 222
a
SCD (13-14). Tema 4. Introducci´n a los sistemas de tiempo real..
o
Implementaci´n de la Planificaci´n C´
o
o
ıclica

§
void ejecutivo_ciclico()
{ int nciclos = 4 ,
frame
= 0 ;
while (true)
{ switch (frame)
{ case 0 : A; B; C;
break
case 1 : A; B; D; E; break
case 2 : A; B; C;
break
case 3 : A; B; D;
break
}
}
frame = (frame+1) % nciclos;
wait_until_next_clock_tick();
} // final del ejecutivo ciclico
¦

¤

;
;
;
;

¥

Propiedades de la Planificaci´n C´
o
ıclica

• No hay concurrencia en la ejecuci´n.
o

◾ Cada ciclo secundario es una secuencia de llamadas a procedimientos
◾ No se necesita un n´cleo de ejecuci´n multitarea
u
o

• Los procedimientos pueden compartir datos.

◾ No se necesitan mecanismos de exclusi´n mutua como los sem´foros o monitores
o
a

• No hace falta analizar el comportamiento temporal.
◾ El sistema es correcto por construcci´n.
o

Problemas de la Planificaci´n C´
o
ıclica

• Dificultad para incorporar tareas con periodos largos.
• Las tareas espor´dicas son dif´
a
ıciles de tratar.

◾ Se puede utilizar un servidor de consulta.

• El plan ciclo del proyecto es dif´ de construir.
ıcil

◾ Si los periodos son de diferentes ´rdenes de magnitud el n´mero de ciclos secundarios se hace
o
u
muy grande.
◾ Puede ser necesario partir una tarea en varios procedimientos.
◾ Es el caso m´s general de sistemas en tiempo real cr´
a
ıticos.

• Es poco flexible y dif´ de mantener.
ıcil

◾ Cada vez que se cambia una tarea hay que rehacer toda la planificaci´n.
o

creado October 4, 2013- p´gina 144 / 222
a
SCD (13-14). Tema 4. Introducci´n a los sistemas de tiempo real..
o

5.2.2

Planificaci´n con prioridades
o

Planificaci´n con prioridades
o

• La prioridad es un mecanismo elemental para planificar la ejecuci´n de un conjunto de tareas.
o

◾ Es un atributo de las tareas normalmente ligado a su importancia relativa en el conjunto de
tareas.
◾ Por convenci´n se asigna n´meros enteros mayores a procesos m´s urgentes.
o
u
a
◾ La prioridad de una tarea la determina sus necesidades temporales; no es importante el rendimiento
o comportamiento del sistema.

• Una tarea puede estar en varios estados:

• Las tareas ejecutables se despachan para su ejecuci´n en orden de
o
prioridad.

Planificaci´n RMS
o

• RMS (Rate Monotonic Scheduling): Es un m´todo de planificaci´n est´tico on-line con asignaci´n
e
o
a
o
de prioridades a las tareas m´s frecuentes.
a
• A cada tarea se le asigna una (´nica) prioridad basada en su periodo; cuanto menor sea el periodo
u
(mayor frecuencia) → mayor prioridad.
∀i, j

Ti < Tj

⇒ Pi < Pj

• Esta asignaci´n de prioridades es optima en el caso de que todas las tareas sean peri´dicas, y el
o
o
plazo de respuesta m´xima D coincida con el periodo.
a

Nota: aqu´ se emplean siempre numeros enteros menores para procesos m´s urgentes o m´s prioritarios.
ı
a
a
Ejemplo de planificaci´n RMS (1)
o

• Dada un conjunto de tres tareas con las siguientes restricciones temporales:
Tareas
1
2
3

C
10
5
9

D
30
40
50

T
40
40
50

• La aplicaci´n del m´todo de planificaci´n RMS indica que la tarea 1 es la que tiene mayor prioridad,
o
e
o
luego la 2, y luego la 3.

creado October 4, 2013- p´gina 145 / 222
a
SCD (13-14). Tema 4. Introducci´n a los sistemas de tiempo real..
o
Ejemplo de planificaci´n RMS (2)
o

• Para analizar la planificabilidad del sistema con dichas restricciones, hay que estudiar en el cronograma
que:
◾ Para cada tarea:

→ Ri < Ti

• Solo hay que probar la ejecuci´n correcta de todas las tareas en el hiperperiodo, es decir, H = mcm(Ti).
o
◾ Si se cumple en el hiperperiodo, se repetir´ indefinidamente.
a

1
2
3
0

20

40

60

80

100

120

140

160

Planificaci´n EDF
o

• EDF (Earliest Deadline First, primero al m´s urgente): La asignaci´n de prioridad se establece una
a
o
prioridad m´s alta a la que se encuentre m´s pr´xima a su plazo de respuesta m´xima (deadline). En
a
a
o
a
caso de igualdad se hace una elecci´n no determinista de la siguiente tarea a ejecutar.
o
• Es un algoritmo de planificaci´n din´mica, dado que la prioridad de cada tarea cambia durante la
o
a
evoluci´n del sistema.
o
• Es m´s ´ptimo porque no es necesario que las tareas sean peri´dicas.
a o
o
• En menos pesimista que RMS.

Ejemplo de planificaci´n EDF
o

creado October 4, 2013- p´gina 146 / 222
a
SCD (13-14). Tema 4. Introducci´n a los sistemas de tiempo real..
o
Tareas
J1
J2

EDF

J1 1

RMS

J1

2

4

2
6

2
2

6

12

14

1
2

4

1
2

8
10
fallo

1

J2

D
5
7

1

2
1

0

T
5
7

1

J2
0

C
2
4

2
10

16

18

20

1

2
8

2

12

2
14

22

1
2

16

18

20

22

creado October 4, 2013- p´gina 147 / 222
a
SCD (13-14). Tema 4. Introducci´n a los sistemas de tiempo real..
o

creado October 4, 2013- p´gina 148 / 222
a
Part III

Seminarios y guiones de pr´cticas
a

149
Scd 13-14 todo
Chapter 6

Seminario 1. Programaci´n multihebra y
o
sincronizaci´n con sem´foros.
o
a
Introducci´n
o

Este seminario tiene cuatro partes, inicialmente se repasa el concepto de hebra, a continuaci´n se da una
o
breve introducci´n a la interfaz (posix) de las librer´ de hebras disponibles en linux. A continuaci´n, se
o
ıas
o
estudia el mecanismo de los sem´foros como herramienta para solucionar problemas de sincronizaci´n y, por
a
o
ultimo, se hace una introducci´n a una librer´ para utilizar sem´foros con hebras posix.
´
o
ıa
a

• El objetivo es conocer algunas llamadas b´sicas de dicho interfaz para el desarrollo de ejemplos
a
sencillos de sincronizaci´n con hebras usando sem´foros (pr´ctica 1)
o
a
a

• Las partes relacionadas con hebras posix est´n basadas en el texto disponible en esta web: https://computing.llnl.gov
a

6.1

Concepto e Implementaciones de Hebras

Procesos: estructura

En un sistema operativo pueden existir muchos procesos ejecut´ndose concurrentemente, cada proceso cora
responde a un programa en ejecuci´n y tiene su propio flujo de control.
o
• Cada proceso ocupa una zona de memoria con (al menos) estas partes:

◾ texto: zona con la secuencia de instrucciones que se est´n ejecutando.
a

◾ datos: espacio (de tama˜o fijo) ocupado por variables globales.
n

◾ pila: espacio (de tama˜o cambiante) ocupado por variables locales.
n
◾ mem. din´mica (heap): espacio ocupado por variables din´micas.
a
a

• Cada proceso tiene asociados (entre otros) estos datos:

◾ contador de programa (pc): dir. en memoria (zona de texto) de la siguiente instrucci´n a ejecutar.
o
◾ puntero de pila (sp): dir. en memoria (zona de pila) de la ultima posici´n ocupada por la pila.
´
o
151
SCD (13-14). Seminario 1. Programaci´n multihebra y sincronizaci´n con sem´foros..
o
o
a
Diagrama de la estructura de los procesos

Podemos visualizarla (simplificadamente) como sigue:
Proceso 0

Proceso n

Proceso 1

pc

pc

pc

sp

sp

sp

texto

texto

texto

......
datos
pila

datos

datos
pila

pila
heap

heap
heap

Ejemplo de un proceso

En el siguiente programa escrito en C/C++, el estado del proceso (durante la ejecuci´n de k=1;) es el que
o
se ve a la derecha:
§
int a,b,c ; // variables globales

void subprograma1()
{
int i,j,k ; // vars. locales (1)
k = 1 ;
}
void subprograma2()
{
float x ; // vars. locales (2)
subprograma1() ;
}
int main()
{
char * p = new char ; // ”p” local
*p = ’a’; // ”*p” en el heap
subprograma2() ;
}
¦

¤

Proceso

pc
sp
texto
…
k=1;
…
datos
a,b,c
pila
p
x
i,j,k
heap
*p
¥

Procesos y hebras

La gesti´n de varios procesos no independientes (cooperantes) es muy util pero consume una cantidad
o
´
apreciable de recursos del SO:
• Tiempo de procesamiento para repartir la CPU entre ellos

creado October 4, 2013- p´gina 152 / 222
a
SCD (13-14). Seminario 1. Programaci´n multihebra y sincronizaci´n con sem´foros..
o
o
a
• Memoria con datos del SO relativos a cada proceso

• Tiempo y memoria para comunicaciones entre esos procesos

para mayor eficiencia en esta situaci´n se dise˜´ el concepto de hebra:
o
no
• Un proceso puede contener una o varias hebras.

• Una hebra es un flujo de control en el texto (com´n) del proceso al que pertencen.
u
• Cada hebra tiene su propia pila (vars. locales), vac´ al inicio.
ıa

• Las hebras de un proceso comparten la zona de datos (vars. globales), y el heap.

Diagrama de la estructura de procesos y hebras

Podriamos visualizarlos (simplificadamente) como sigue:
Proceso 0

Proceso 1

texto

texto

datos

datos

heap

heap

Hebra 0

Hebra 0

Hebra 1

pc

pc

pc

sp

sp

sp

pila

pila

pila

..........

.....

Inicio y finalizaci´n de hebras
o

Al inicio de un programa, existe una unica hebra (que ejecuta la funci´n main en C/C++). Durante la
´
o
ejecuci´n del programa:
o
• Una hebra A en ejecuci´n puede crear otra hebra B en el mismo proceso de A.
o

• Para ello, A designa un subprograma f (una funci´n C/C++) del texto del proceso, y despu´s contin´a
o
e
u
su ejecuci´n. La hebra B:
o
◾ ejecuta el subprograma f concurrentemente con el resto de hebras.

◾ termina normalmente cuando finaliza de ejecutar dicho subprograma

creado October 4, 2013- p´gina 153 / 222
a
SCD (13-14). Seminario 1. Programaci´n multihebra y sincronizaci´n con sem´foros..
o
o
a

• Una hebra puede finalizar en cualquier momento (antes de terminar el subprograma con que se inici´).
o
• Una hebra puede finalizar otra hebra en ejecuci´n B, sin esperar que termine
o
• Una hebra puede esperar a que cualquier otra hebra en ejecuci´n finalice.
o

Ejemplo de estado de un proceso con tres hebras

En main se crean dos hebras, despu´s se llega al estado que vemos:
e

§
int a,b,c ;

¤

Proceso

void subprograma1()
{
int i,j,k ;
// ...
}
void subprograma2()
{
float x ;
// ...
}
int main()
{
char * p = new char ;
// cr.he.subp.2
// cr.he.subp.1
// ...
}
¦

6.2

6.2.1

texto
subprograma1(){ … }
subprograma2(){ … }
main() { … }
datos
a,b,c
heap
*p
Hebra 0

Hebra 1

Hebra 2

pc

pc

pc

sp

sp

sp

pila
p

pila
x

pila
i,j,k

¥

Hebras POSIX
Introducci´n
o

Introducci´n
o

En esta secci´n veremos algunas llamadas b´sicas de la parte de hebras de POSIX (IEEE std 1003.1), en
o
a
la versi´n de 2004:
o

• El est´ndar POSIX define los par´metros y la sem´ntica de un amplio conjunto de funciones para
a
a
a
diversos servicios del SO a los programas de usuario.
◾ http://pubs.opengroup.org/onlinepubs/009695399/

• Una parte de las llamadas de POSIX est´n dedicadas a gesti´n (creaci´n, finalizaci´n, sincronizaci´n,
a
o
o
o
o
etc...) de hebras, son las que aparecen aqu´
ı:
◾ http://pubs.opengroup.org/onlinepubs/009695399/idx/threads.html

creado October 4, 2013- p´gina 154 / 222
a
SCD (13-14). Seminario 1. Programaci´n multihebra y sincronizaci´n con sem´foros..
o
o
a
La librer´ NPTL
ıa

Los ejemplos se han probado usando la Native POSIX Thread Library (NTPL) en Linux (ubuntu), que
implementa la parte de hebras de la versi´n de 2004 de POSIX
o
• Est´ disponible para Linux desde el kernel 2.6 (2004).
a

• En esta implementaci´n una hebra POSIX se implementa usando una hebra del kernel de Linux (se
o
dice que las hebras POSIX son 1-1).
• Como consecuencia de lo anterior, hebras distintas de un mismo proceso pueden ejecutarse en procesadores distintos,

• Por tanto, este tipo de hebras constituyen una herramienta ideal para el desarrollo de aplicaciones que
pueden aprovechar el potencial de rendimiento que ofrecen los sistemas multiprocesador (o multin´cleo)
u
con memoria compartida.

6.2.2

Creaci´n y finalizaci´n de hebras
o
o

Creaci´n de hebras con pthread create
o

Esta funci´n sirve para crear una nueva hebra, su declaraci´n es como sigue:
o
o

§
¦

int pthread_create( pthread_t *thread, const pthread_attr_t *attr,
void *(*start_routine)(void*), void *arg);

Par´metros (m´s informaci´n aqu´
a
a
o
ı):
nombre
thread

tipo
pthread t *

start routine
arg

void *nombre(void *)
void *

attr

attr t *

Ejemplo de creaci´n de hebras.
o

¤
¥

descripci´n
o
para referencias posteriores en las
operaciones sobre la hebra
atributos de la hebra (puede
ser NULL para valores por def.)
funci´n a ejecutar por la hebra
o
puntero que se pasa como
par´metro para start routine
a
(puede ser NULL).

En el siguiente ejemplo se crean dos hebras:

§
#include <iostream>
#include <pthread.h>
using namespace std ;

¤

void* proc1( void* arg )
{ for( unsigned long i = 0 ; i < 5000 ; i++ )
cout << "hebra 1, i == " << i << endl ;
return NULL ;
}

creado October 4, 2013- p´gina 155 / 222
a
SCD (13-14). Seminario 1. Programaci´n multihebra y sincronizaci´n con sem´foros..
o
o
a

void* proc2( void* arg )
{ for( unsigned long i = 0 ; i < 5000 ; i++ )
cout << "hebra 2, i == " << i << endl ;
return NULL ;
}
int main()
{
pthread_t hebra1, hebra2 ;
pthread_create(&hebra1,NULL,proc1,NULL);
pthread_create(&hebra2,NULL,proc2,NULL);
// ... finalizacion ....
}
¦

¥

Finalizaci´n de hebras
o

Una hebra finaliza cuando:

• termina la funci´n designada en pthread create (solo para hebras distintas de la inicial, en estos casos
o
es equivalente a llamar a pthread exit).

• llama a pthread exit expl´
ıcitamente

• es terminada por otra hebra con una llamada a pthread cancel

• el proceso (de esta hebra) termina debido a una llamada a exit desde cualquier hebra de dicho proceso.

• la hebra inicial termina main sin haber llamado a pthread exit (es decir, para permitir que las hebras
creadas contin´en al acabar la hebra inicial, es necesario que dicha hebra principal llame a pthread exit
u
antes del fin de main)

La funci´n pthread exit
o

o
La funci´n pthread exit causa la finalizaci´n de la hebra que la llama:
o

§
void pthread_exit( void* value_ptr );
¦

Par´metros:
a
nombre
tipo
value ptr void *
m´s informaci´n:
a
o

descripci´n
o
puntero que recibir´ la hebra que espere (v´
a
ıa
join) la finalizaci´n de esta hebra (si hay alguna)
o
(puede ser NULL)

http://pubs.opengroup.org/onlinepubs/009695399/functions/pthread exit.html

Ejemplo de pthread exit

El ejemplo anterior se puede completar as´
ı:
creado October 4, 2013- p´gina 156 / 222
a

¤
¥
SCD (13-14). Seminario 1. Programaci´n multihebra y sincronizaci´n con sem´foros..
o
o
a

§
#include <iostream>
#include <pthread.h>
using namespace std ;

void* proc1( void* arg )
{ for( unsigned long i = 0 ; i < 5000 ; i++ )
cout << "hebra 1, i == " << i << endl ;
return NULL ;
}
void* proc2( void* arg )
{ for( unsigned long i = 0 ; i < 5000 ; i++ )
cout << "hebra 2, i == " << i << endl ;
return NULL ;
}
int main()
{
pthread_t hebra1, hebra2 ;
pthread_create(&hebra1,NULL,proc1,NULL);
pthread_create(&hebra2,NULL,proc2,NULL);
pthread_exit(NULL); // permite continuar a hebra1 y hebra2
}
¦

6.2.3

¤

¥

Sincronizaci´n mediante uni´n
o
o

La operaci´n de uni´n.
o
o

POSIX provee diversos mecanismos para sincronizar hebras, veremos dos de ellos:
• Usando la operaci´n de uni´n (join).
o
o
• Usando sem´foros.
a

La operaci´n de uni´n permite que (mediante una llamada a pthread join) una hebra A espere a que otra
o
o
hebra B termine:
• A es la hebra que invoca la uni´n, y B la hebra objetivo.
o

• Al finalizar la llamada, la hebra objetivo ha terminado con seguridad.
• Si B ya ha terminado, no se hace nada.

• Si la espera es necesaria, se produce sin que la hebra que llama (A) consuma CPU durante dicha
espera (A queda suspendida).

La funci´n pthread join
o

La funci´n pthread join est´ declarada como sigue:
o
a

§
int pthread_join( pthread_t thread, void **value_ptr );
¦

creado October 4, 2013- p´gina 157 / 222
a

¤
¥
SCD (13-14). Seminario 1. Programaci´n multihebra y sincronizaci´n con sem´foros..
o
o
a

Par´metros y resultado:
a

nombre
thread
value ptr

resultado

tipo
thread t
void **

int

descripci´n
o
identificador de la hebra objetivo
puntero a la variable que recibir´ el dato (de
a
tipo void *) enviado por la hebra objetivo
al finalizar (v´ return o pthread exit)
ıa
0 si no hay error, en caso contrario
se devuelve un c´digo de error.
o

m´s informaci´n aqu´ http://pubs.opengroup.org/onlinepubs/009695399/functions/pthread join.html
a
o
ı:

Ejemplo de pthread join

Puede ser util, por ejemplo, para que la hebra principal realice alg´n procesamiento posterior a la finalizaci´n
´
u
o
de las hebras:

§
#include <pthread.h>

¤

void* proc1( void* arg ) { /∗ .... ∗/ }
void* proc2( void* arg ) { /∗ .... ∗/ }
int main()
{
pthread_t hebra1, hebra2 ;

pthread_create(&hebra1,NULL,proc1,NULL);
pthread_create(&hebra2,NULL,proc2,NULL);
pthread_join(hebra1,NULL);
pthread_join(hebra2,NULL);

}
¦

// calculo posterior a la finalizacion de las hebras.....

6.2.4

¥

Par´metros e identificaci´n de hebras
a
o

Hebras id´nticas
e

En muchos casos, un problema se puede resolver con un proceso en el que varias hebras distintas ejecutan
el mismo algoritmo con distintos datos de entrada. En estos casos
• Es necesario que cada hebra reciba par´metros distintos
a

• Esto se puede hacer a traves del par´metro de tipo void * que recibe el subprograma que ejecuta una
a
hebra.

• Dicho par´metro suele ser un ´
a
ındice o un puntero que permita a la hebra recuperar el conjunto de
par´metros de entrada de una estructura de datos en memoria compartida, inicializada por la hebra
a
principal (si es un ´
ındice entero, es necesario convertirlo hacia/desde el tipo void *)

• La estructura puede usarse para guardar tambi´n resultados de la hebra, o en general datos de la
e
misma que deban ser le´
ıdos por otras.

creado October 4, 2013- p´gina 158 / 222
a
SCD (13-14). Seminario 1. Programaci´n multihebra y sincronizaci´n con sem´foros..
o
o
a
Ejemplo b´sico de paso de par´metros a hebras
a
a

10 hebras ejecutan concurrentemente func(0), func(1), . . . , func(9)

§
#include <iostream>
#include <pthread.h>
using namespace std ;

¤

const unsigned num_hebras = 10 ;
unsigned long func( unsigned long n ) { /∗ ..calculo arbitrario.. ∗/ }
void* proc( void* i ) { return (void *) func( (unsigned long)(i) ) ; }
int main()
{
pthread_t id_hebra[num_hebras] ;
for( unsigned i = 0 ; i < num_hebras ; i++ )
pthread_create( &(id_hebra[i]), NULL, proc, (void *)i );
for( unsigned i = 0 ; i < num_hebras ; i++ )
{
unsigned long resultado ;
pthread_join( id_hebra[i], (void **) (&resultado) );
cout << "func(" << i << ") == " << resultado << endl
}

;

}
¦

¥

(nota: solo funciona si sizeof(unsigned long)==sizeof(void *))

6.2.5

Ejemplo de hebras: c´lculo num´rico de integrales
a
e

C´lculo de num´rico de integrales
a
e

La programaci´n concurrente puede ser usada para resolver m´s r´pidamente multitud de problemas, entre
o
a a
ellos los que conllevan muchas operaciones con n´meros flotantes
u

• Un ejemplo t´
ıpico es el c´lculo del valor I de la integral de una funci´n f de variable real (entre 0 y
a
o
1, por ejemplo ) y valores reales positivos:
I =

∫

0

1

f (x) dx

• El c´lculo se puede hacer evaluando la funci´n f en un conjunto de m puntos uniformemente espaciados
a
o
en el intervalo [0, 1], y aproximando I como la media de todos esos valores:
I ≈

Interpretaci´n geom´trica
o
e

1 m−1
∑ f (xi )
m i=0

donde:

xi =

i + 1/2
m

Aproximamos el area azul (es I) (izquierda), usando la suma de las areas de las m barras (derecha):
´
´
creado October 4, 2013- p´gina 159 / 222
a
SCD (13-14). Seminario 1. Programaci´n multihebra y sincronizaci´n con sem´foros..
o
o
a

y = f (x)

y = f (x)

x

x

• Cada punto de muestra es el valor xi (puntos negros)

• Cada barra tiene el mismo ancho 1/m, y su altura es f (xi ).

C´lculo secuencial del n´mero π
a
u

Para verificar la correcci´n del m´todo, se puede usar una integral I con valor conocido. A modo de ejemplo,
o
e
usaremos una funci´n f cuya integral entre 0 y 1 es el n´mero π:
o
u
I = π =

∫

1

0

4
dx
1 + x2

aqu´ f (x) =
ı

4
1 + x2

una implementaci´n secuencial sencilla ser´ mediante esta funci´n:
o
ıa
o

§
unsigned long m = ..... ;

// n´mero de muestras
u

double f( double x )
// implementa funci´n f
o
{ return 4.0/(1+x*x) ;
//
f (x) = 4/(1 + x2 )
}
double calcular_integral_secuencial( )
{ double suma = 0.0 ;
// inicializar suma
for( unsigned long i = 0 ; i < m ; i++ ) // para cada i entre 0 y m − 1
suma += f( (i+0.5)/m );
//
a˜adir f (xi ) a la suma actual
n
return suma/m ;
// devolver valor promedio de f
}
¦

Versi´n concurrente de la integraci´n
o
o

El c´lculo citado anteriormente se puede hacer mediante un total de n hebras id´nticas (asumimos que m
a
e
es m´ltiplo de n)
u
• Cada una de las hebras evalua f en m/n puntos del dominio

• La cantidad de trabajo es similar para todas, y los c´lculos son independientes.
a

creado October 4, 2013- p´gina 160 / 222
a

¤

¥
SCD (13-14). Seminario 1. Programaci´n multihebra y sincronizaci´n con sem´foros..
o
o
a
• Cada hebra calcula la suma parcial de los valores de f

• La hebra principal recoge las sumas parciales y calcula la suma total.

• En un entorno con k procesadores o n´cleos, el c´lculo puede hacerse hasta k veces m´s r´pido. Esta
u
a
a a
mejora ocurre solo para valores de m varios ´rdenes de magnitud m´s grandes que n.
o
a

Distribuci´n de c´lculos
o
a

Para distribuir los c´lculos entre hebras, hay dos opciones simples, hacerlo de forma contigua (izquierda) o
a
de forma entrelazada (derecha)

y = f (x)

y = f (x)

x

x

Cada valor f (xi ) es calculado por:

• Contigua: la hebra n´mero i/n.
u

• Entrelazada: la hebra n´mero i mod n.
u

Esquema de la implementaci´n concurrente
o

§
const unsigned long m = .... ; // n´mero de muestras
u
const unsigned long n = .... ; // n´mero de hebras
u
double resultado_parcial[n] ; // vector de resultados parciales

double f( double x )
// implementa funci´n f :
o
{ return 4.0/(1+x*x) ;
//
f (x) = 4/(1 + x2 )
}
void * funcion_hebra( void * ih_void ) // funci´n que ejecuta cada hebra
o
{
unsigned long ih = (unsigned long) ih_void ; // n´mero o ´
u
ındice de esta hebra
double sumap = 0.0 ;
// calcular suma parcial en ”sumap”
.....
resultado_parcial[ih] = sumap ; // guardar suma parcial en vector.
}

creado October 4, 2013- p´gina 161 / 222
a

¤
SCD (13-14). Seminario 1. Programaci´n multihebra y sincronizaci´n con sem´foros..
o
o
a

double calcular_integral_concurrente( )
{
// crear y lanzar n hebras, cada una ejecuta ”funcion concurrente”
.....
// esperar (join) a que termine cada hebra, sumar su resultado
.....
// devolver resultado completo
.....
}
¦

¥

Medici´n de tiempos
o

Para apreciar la reducci´n de tiempos que se consigue con la programaci´n concurrente, se pueden medir
o
o
los tiempos que tardan la versi´n secuencial y la concurrente. Para hacer esto con la m´xima precisi´n, se
o
a
o
puede usar la funci´n clock_gettime en linux:
o
• Forma parte de POSIX, en concreto de la extensiones de tiempo real.

• Sirve para medir tiempo real transcurrido entre instantes de la ejecuci´n de un programa con muy alta
o
precisi´n (nanosegundos).
o

• Para facilitar su uso, en lugar de usarla directamente se pueden usar indirectamente a trav´s de otras
e
funciones (que se proporcionan) que permiten calcular ese tiempo como un valor real en segundos,
haciendo abstracci´n de los detalles no relevantes.
o

Uso de las funciones de medici´n de tiempos
o

Para medir el tiempo que tarda un trozo de programa, se puede usar este esquema en C++

§
#include "fun_tiempos.h"
// ....
void funcion_cualquiera( /∗.....∗/ )
{ .....
struct timespec inicio = ahora() ;
....
struct timespec fin = ahora() ;
....
cout << "tiempo transcurrido == "
<< duracion( &inicio, &fin )
<< " seg." << endl ;
}
¦

¤

// inicio = inicio del tiempo a medir
// actividad cuya duracion se quiere medir
// fin = fin del tiempo a medir

// escribe resultados:
// tiempo en segundos entre ”inicio” y ”fin”

los archivos fun_tiempo.h (cabeceras) y fun_tiempo.c (implementaci´n) se encuentran disponibles para
o
los alumnos.
Compilando programas con hebras POSIX

Para compilar un archivo ejemplo.cpp, que use las funciones definidas en fun_tiempos.c (y use hebras
posix), y obtener el archivo ejecutable ejemplo, podemos dar estos pasos:
creado October 4, 2013- p´gina 162 / 222
a

¥
SCD (13-14). Seminario 1. Programaci´n multihebra y sincronizaci´n con sem´foros..
o
o
a

§
gcc -g -c fun_tiempos.c
# compila ”fun tiempos.c” y genera ”fun tiempos.o”
g++ -g -c ejemplo.cpp
# compila ”ejemplo.cpp” y genera ”ejemplo.o”
g++ -o ejemplo ejemplo.o fun_tiempos.o -lrt -lpthread # enlaza, genera ”ejemplo”
¦

• el switch -lrt sirve para enlazar las librer´ correspondientes a la extensi´n de tiempo real de POSIX
ıas
o
(incluye clock_gettime)
• el switch -lpthreads sirve para incluir las funciones de hebras POSIX

• tambi´n es posible integrarlo todo en un makefile y usar make
e

Actividad: medici´n de tiempos de c´lculo concurrente.
o
a

Como actividad para los alumnos en este seminario se propone realizar y ejecutar una implementaci´n sencilla
o
del c´lculo concurrente del n´mero π, tal y como hemos visto aqu´
a
u
ı:

• El programa aceptar´ como par´metros en la l´
a
a
ınea de comandos el n´mero de hebras a lanzar y el
u
n´mero de muestras
u

• En la salida se presenta el valor exacto de π y el calculado (sirve para verificar si el programa es
correcto, ya que deben diferir por muy poco para un n´mero de muestras del orden de cientos o miles)
u
• Asimismo , el programa imprimir´ la duraci´n del c´lculo concurrente y el secuencial.
a
o
a

Se debe razonar acerca de como el n´mero de procesadores disponibles y el n´mero de hebras afecta
u
u
al tiempo del c´lculo concurrente en relaci´n al secuencial (en Linux, para conocer el n´mero de CPUs
a
o
u
disponibles y sus caracter´
ısticas, se puede ver el archivo /proc/cpuinfo)

6.3

Introducci´n a los Sem´foros
o
a

Sem´foros
a

Los sem´foros constituyen un mecanismo de nivel medio que permite solucionar los problemas derivados de
a
la ejecuci´n concurrente de procesos no independientes. Sus caracter´
o
ısticas principales son:
• permite bloquear los procesos sin mantener ocupada la CPU

• resuelven f´cilmente el problema de exclusi´n mutua con esquemas de uso sencillos
a
o

• se pueden usar para resolver problemas de sincronizaci´n (aunque en ocasiones los esquemas de uso
o
son complejos)
• el mecanismo se implementa mediante instancias de una estructura de datos a las que se accede
unicamente mediante subprogramas espec´
´
ıficos.

creado October 4, 2013- p´gina 163 / 222
a

¤

¥
SCD (13-14). Seminario 1. Programaci´n multihebra y sincronizaci´n con sem´foros..
o
o
a
Estructura de un sem´foro
a

Un sem´foro es un instancia de una estructura de datos (un registro) que contiene los siguientes elementos:
a
• Un conjunto de procesos bloqueados (se dice que est´n esperando en el sem´foro).
a
a
• Un valor natural (entero no negativo), al que llamaremos valor del sem´foro
a

Estas estructuras de datos residen en memoria compartida. Al principio de un programa que use sem´foros,
a
debe poder inicializarse cada uno de ellos:
• el conjunto de procesos asociados (bloqueados) estar´ vac´
a
ıo
• se deber´ indicar un valor inicial del sem´foro
a
a

Operaciones sobre los sem´foros
a

Adem´s de la inicializaci´n, solo hay dos operaciones b´sicas que se pueden realizar sobre una variable de
a
o
a
tipo sem´foro (que llamamos s) :
a
• sem wait(s)

◾ Si el valor de s es mayor que cero, decrementar en una unidad dicho valor
◾ Si el valor de s es cero, bloquear el proceso que la invoca en el conjunto de procesos bloqueados
asociado a s

• sem signal(s)

◾ Si el conjunto de procesos bloqueados asociado a s no est´ vac´ desbloquear uno de dichos
a
ıo,
procesos.
◾ Si el conjunto de procesos bloqueados asociado a s est´ vac´ incrementar en una unidad el valor
a
ıo,
de s.

En un sem´foro cualquiera, estas operaciones se ejecutan de forma at´mica, es decir, no puede haber dos
a
o
procesos distintos ejecutando estas operaciones a la vez sobre un mismo sem´foro (excluyendo el per´
a
ıodo de
bloqueo que potencialmente conlleva la llamada a sem wait).
Uso de sem´foros para exclusi´n mutua
a
o

Los sem´foros se pueden usar para EM usando un sem´foro inicializado a 1, y haciendo sem wait antes de
a
a
e
o
ıtica:
la secci´n cr´
o
ıtica y sem signal despu´s de la secci´n cr´

§
{ variables compartidas y valores iniciales }
var sc_libre : semaphore := 1 ; { 1 si SC esta libre, 0 si SC esta ocupada }
¦
§
while true do begin
sem_wait( sc_libre
); { esperar bloqueado hasta que ’sc libre’ sea 1 }
{ seccion critica : ...... }
sem_signal( sc_libre ); { desbl. proc. en espera o poner ’sc libre’ a 1 }
{ resto seccion : ....... }
end
¦

En cualquier instante de tiempo, la suma del valor del sem´foro m´s el n´mero de procesos en la SC es la
a
a
u
unidad. Por tanto, solo puede haber 0 o 1 procesos en SC, y se cumple la exclusi´n mutua.
o

creado October 4, 2013- p´gina 164 / 222
a

¤
¥
¤

¥
SCD (13-14). Seminario 1. Programaci´n multihebra y sincronizaci´n con sem´foros..
o
o
a
Uso de sem´foros para sincronizaci´n
a
o

El problema del Productor-Consumidor se puede resolver f´cilmente con sem´foros:
a
a

§
{ variables compartidas
var
x
:
producidos
:
consumidos
:
puede_leer
:
puede_escribir :
¦

integer ;
integer
integer
semaphore
semaphore

:=
:=
:=
:=

0
0
0
1

;
;
;
;

{
{
{
{
{

§
{ Proceso Productor ( calcula ”x ”) }
var a : integer ;
begin
while true begin
a := ProducirValor() ;
sem_wait( puede_escribir );
x := a ; { sentencia E }
producidos := producidos + 1 ;
sem_signal( puede_leer ) ;
end
end
¦

6.4

¤

}

contiene cada valor producido
}
numero de valores producidos
}
numero de valores consumidos
}
1 si se puede leer ”x”, 0 si no
}
1 si se puede escribir ”x”, 0 si no }

¤
§
{ Proceso Consumidor (lee ”x ”) }
var b : integer ;
begin
while true do begin
sem_wait( puede_leer ) ;
b := x ; { sentencia L }
consumidos := consumidos + 1 ;
sem_signal( puede_escribir ) ;
UsarValor(b) ;
end
end
¥
¦

¥
¤

¥

Sincronizaci´n de hebras con sem´foros POSIX
o
a

Introducci´n
o

Una parte de las llamadas del est´ndard POSIX son utiles para gestionar sem´foros para sincronizaci´n de
a
´
a
o
hebras o de procesos.
Veremos las llamadas b´sicas que permiten sincronizar hebras en un proceso. Son las siguientes:
a
• sem init: inicializa un sem´foro (dando el valor inicial)
a
• sem wait: realiza la operaci´n wait sobre un sem´foro
o
a

• sem post: realiza la operaci´n signal sobre un sem´foro
o
a

• sem getvalue: devuelve el valor actual de un sem´foro
a

• sem destroy: destruye un sem´foro y libera la memoria ocupada.
a

6.4.1

Funciones b´sicas.
a

La funci´n sem init
o

La funci´n sem init est´ declarada como sigue:
o
a

§
int sem_init( sem_t* sem, int pshared, unsigned value );
¦

creado October 4, 2013- p´gina 165 / 222
a

¤
¥
SCD (13-14). Seminario 1. Programaci´n multihebra y sincronizaci´n con sem´foros..
o
o
a
Par´metros y resultado:
a
nombre
sem
pshared

value
resultado

tipo
sem t *
int

unsigned
int

descripci´n
o
puntero al identificador del sem´foro
a
distinto de cero solo si el sem´foro
a
ser´ compartido con otros procesos.
a
valor inicial
0 si se ha inicializado el sem´foro, en caso
a
contrario es un c´digo de error.
o

m´s informaci´n aqu´ http://pubs.opengroup.org/onlinepubs/009695399/functions/sem init.html
a
o
ı:

La funci´n sem wait
o

a
La funci´n sem wait est´ declarada como sigue:
o

§
int sem_wait( sem_t* sem );
¦

¤
¥

Par´metros y resultado:
a
nombre
sem
resultado

tipo
sem t *
int

descripci´n
o
puntero al identificador del sem´foro
a
0 solo si no ha habido error

m´s informaci´n aqu´ http://pubs.opengroup.org/onlinepubs/009695399/functions/sem wait.html
a
o
ı:

La funci´n sem post
o

a
La funci´n sem post est´ declarada como sigue:
o

§
int sem_post( sem_t* sem );
¦

¤
¥

Par´metros y resultado:
a
nombre
sem
resultado

tipo
sem t *
int

descripci´n
o
puntero al identificador del sem´foro
a
0 solo si no ha habido error

Nota: la selecci´n de la hebra a desbloquear (si hay alguna) depende de los parametros de scheduling
o
asignados a la hebra (normalmente es FIFO).
M´s informaci´n aqu´ http://pubs.opengroup.org/onlinepubs/009695399/functions/sem post.html
a
o
ı:
La funci´n sem getvalue
o

La funci´n sem getvalue est´ declarada como sigue:
o
a

§
int sem_getvalue( sem_t* sem, int* sval );
¦

¤
¥

Par´metros y resultado:
a
creado October 4, 2013- p´gina 166 / 222
a
SCD (13-14). Seminario 1. Programaci´n multihebra y sincronizaci´n con sem´foros..
o
o
a
nombre
sem
sval
resultado

tipo
sem t *
int *
int

descripci´n
o
puntero al identificador del sem´foro
a
puntero a la variable donde se almacena el valor
0 solo si no ha habido error

Nota: al finalizar la llamada, el valor del sem´foro podr´ ya ser distinto del valor le´ (es importante
a
ıa
ıdo
tenerlo en cuenta).
M´s informaci´n aqu´ http://pubs.opengroup.org/onlinepubs/009695399/functions/sem getvalue.html
a
o
ı:

La funci´n sem destroy
o

La funci´n sem destroy est´ declarada como sigue:
o
a

§
int sem_destroy( sem_t* sem ) ;
¦

¤
¥

Par´metros y resultado:
a
nombre
sem
resultado

tipo
sem t *
int

descripci´n
o
puntero al identificador del sem´foro
a
0 solo si no ha habido error

Solo se aplica a sem´foros inicializados con sem init en los cuales no hay hebras esperando. Despu´s de
a
e
destruir un sem´foro, se puede reusar haciendo sem init.
a

M´s informaci´n aqu´ http://pubs.opengroup.org/onlinepubs/009695399/functions/sem destroy.html
a
o
ı:

6.4.2

Exclusi´n mutua
o

Ejemplo de exclusi´n mutua con sem´foros POSIX
o
a

Los sem´foros se pueden usar para exclusi´n mutua, por ejemplo,
a
o

En este ejemplo, se usa un sem´foro (de nombre mutex) inicializado a 1, para escribir en la salida est´ndar
a
a
una l´
ınea completa sin interrupciones.

§
#include <iostream>
#include <pthread.h>
#include <semaphore.h>
using namespace std ;

¤

sem_t mutex ; // semaforo en memoria compartida

void* proc( void* p )
{
sem_wait( &mutex );
cout << "hebra numero: " << ((unsigned long) p) << ". " << endl ;
sem_post( &mutex );
return NULL ;
}
....
¦

¥

creado October 4, 2013- p´gina 167 / 222
a
SCD (13-14). Seminario 1. Programaci´n multihebra y sincronizaci´n con sem´foros..
o
o
a
Ejemplo de exclusi´n mutua con sem´foros POSIX (2)
o
a

El procedimiento principal debe inicializar el sem´foro y crear las hebras, como se incluye aqu´
a
ı:

§
...

¤

int main()
{
const unsigned num_hebras = 50 ;
pthread_t id_hebra[num_hebras] ;
sem_init( &mutex, 0, 1 );
for( unsigned i = 0 ; i < num_hebras ; i++ )
pthread_create( &(id_hebra[i]), NULL, proc, (void *)i );
for( unsigned i = 0 ; i < num_hebras ; i++ )
pthread_join( id_hebra[i], NULL );
sem_destroy( &mutex );
}
¦

6.4.3

¥

Sincronizaci´n
o

Ejemplo de sincronizaci´n con sem´foros POSIX
o
a

En este otro ejemplo, hay una hebra que escribe una variable global y otra que la lee (cada una en un bucle).
Se usan dos sem´foros para evitar dos lecturas o dos escrituras seguidas, y adem´s otro para exclusi´n m´tua
a
a
o u
en las escrituras al terminal:

§
sem_t
puede_escribir, // inicializado a 1
puede_leer,
// inicializado a 0
mutex ;
// inicializado a 1

¤

unsigned long
valor_compartido ; // valor para escribir o leer
const unsigned long
num_iter = 10000 ; // numero de iteraciones

......
¦

¥

Ejemplo de sincronizaci´n con sem´foros POSIX (2)
o
a

La hebra escritora espera que se pueda escribir, entonces escribe y se˜ala que se puede leer:
n

§
...

void* escribir( void* p )
{

creado October 4, 2013- p´gina 168 / 222
a

¤
SCD (13-14). Seminario 1. Programaci´n multihebra y sincronizaci´n con sem´foros..
o
o
a
unsigned long contador = 0 ;

for( unsigned long i = 0 ; i <
{
contador = contador + 1 ; //
sem_wait( &puede_escribir )
valor_compartido = contador
sem_post( &puede_leer ) ;

num_iter ; i++ )
genera un nuevo valor
;
; // escribe el valor

sem_wait( &mutex ) ;
cout << "valor escrito == " << contador << endl << flush ;
sem_post( &mutex ) ;
}
return NULL ;
}
...
¦

¥

Ejemplo de sincronizaci´n con sem´foros POSIX (3)
o
a

La hebra lectora espera a que se pueda leer, entonces lee y se˜ala que se puede escribir:
n

§
....

¤

void* leer( void* p )
{
unsigned long valor_leido ;
for( unsigned long i = 0 ; i < num_iter ; i++ )
{
sem_wait( &puede_leer ) ;
valor_leido = valor_compartido ; // lee el valor generado
sem_post( &puede_escribir ) ;
sem_wait( &mutex ) ;
cout << "valor leido
sem_post( &mutex ) ;

== " << valor_leido << endl << flush ;

}
return NULL ;
}
...
¦

¥

Ejemplo de sincronizaci´n con sem´foros POSIX (4)
o
a

El procedimiento main crea los sem´foros y hebras y espera que terminen:
a

§
....

int main()
{

creado October 4, 2013- p´gina 169 / 222
a

¤
SCD (13-14). Pr´ctica 1. Sincronizaci´n de hebras con sem´foros..
a
o
a
pthread_t hebra_escritora, hebra_lectora ;

sem_init( &mutex, 0, 1 ) ; // semaforo para EM: inicializado a 1

sem_init( &puede_escribir, 0, 1); // inicialmente se puede escribir
sem_init( &puede_leer,
0, 0); // inicialmente no se puede leer

pthread_create( &hebra_escritora, NULL, escribir, NULL );
pthread_create( &hebra_lectora,
NULL, leer,
NULL );
pthread_join( hebra_escritora, NULL ) ;
pthread_join( hebra_lectora,
NULL ) ;
sem_destroy( &puede_escribir );
sem_destroy( &puede_leer );
}
¦

¥

creado October 4, 2013- p´gina 170 / 222
a
Chapter 7

Pr´ctica 1. Sincronizaci´n de hebras con
a
o
sem´foros.
a
7.1

Objetivos

Objetivos.

En esta pr´ctica se realizar´n dos implementaciones de dos problemas sencillos de sincronizaci´n usando
a
a
o
librer´ abiertas para programaci´n multihebra y sem´foros. Los objetivos son:
ıas
o
a
• Conocer el problema del productor-consumidor y sus aplicaciones.
◾ Dise˜ar una soluci´n al problema basada en sem´foros.
n
o
a

◾ Implementar esa soluci´n en un programa C/C++ multihebra, usando la funcionalidad de la
o
librer´ POSIX para:
ıa
▸ la creaci´n y destrucci´n de hebras
o
o
▸ la sincronizaci´n de hebras usando sem´foros
o
a

• Conocer un problema sencillo de sincronizaci´n de hebras (el problema de los fumadores)
o

◾ Dise˜ar una soluci´n basada en sem´foros, teniendo en cuenta los problemas que pueden aparen
o
a
cer.

7.2

7.2.1

◾ Implementar la soluci´n a dicho problema en C/C++ usando hebras y sem´foros POSIX.
o
a

El problema del productor-consumidor
Descripci´n del problema.
o

Problema y aplicaciones

El problema del productor consumidor surge cuando se quiere dise˜ar un programa en el cual un proceso o
n
hebra produce items de datos en memoria que otro proceso o hebra consume.
• Un ejemplo ser´ una aplicaci´n de reproducci´n de v´
ıa
o
o
ıdeo:
171
SCD (13-14). Pr´ctica 1. Sincronizaci´n de hebras con sem´foros..
a
o
a

◾ El productor se encarga de leer de disco o la red y descodificar cada cuadro de v´
ıdeo.

◾ El consumidor lee los cuadros descodificados y los env´ a la memoria de v´
ıa
ıdeo para que se
muestren en pantalla

hay muchos ejemplos de situaciones parecidas.

• En general, el productor calcula o produce una secuencia de items de datos (uno a uno), y el consumidor
lee o consume dichos items (tambien uno a uno).
• El tiempo que se tarda en producir un item de datos puede ser variable y en general distinto al que
se tarda en consumirlo (tambi´n variable).
e

Soluci´n de dos hebras con un vector de items
o

Para dise˜ar un programa que solucione este problema:
n

• Suele ser conveniente implementar el productor y el consumidor como dos hebras independientes, ya
que esto permite tener ocupadas las CPUs disponibles el m´ximo de tiempo,
a
• se puede usar una variable compartida que contiene un ´
ıtem de datos,

• las esperas asociadas a la lectura y la escritura pueden empeorar la eficiencia. Esto puede mejorarse
usando un vector que pueda contener muchos items de datos producidos y pendientes de leer.

Condici´n de sincronizaci´n
o
o

En esta situaci´n, la implementaci´n debe asegurar que :
o
o

• cada ´
ıtem producido es le´ (ning´n ´
ıdo
u ıtem se pierde)
• ning´n ´
u ıtem se lee m´s de una vez.
a

lo cual implica:

• el productor tendr´ que esperar antes de poder escribir en el vector cuando haya creado un ´
a
ıtem pero
el vector est´ completamente ocupado por ´
e
ıtems pendientes de leer

• el consumidor debe esperar cuando vaya a leer un ´
ıtem del vector pero dicho vector no contenga ning´n
u
´
ıtem pendiente de leer.
• en algunas aplicaciones el orden de lectura debe coincidir con el de escritura, en otras podr´ ser
ıa
irrelevante.

7.2.2

Plantillas de c´digo
o

Simplificaciones

En esta pr´ctica se dise˜ar´ e implementar´ un ejemplo sencillo en C/C++
a
n a
a
• cada ´
ıtem de datos ser´ un valor entero de tipo int,
a

creado October 4, 2013- p´gina 172 / 222
a
SCD (13-14). Pr´ctica 1. Sincronizaci´n de hebras con sem´foros..
a
o
a

• el orden en el que se leen los items es irrelevante (en principio),

• el productor produce los valores enteros en secuencia, empezando en 1,

• el consumidor escribe cada valor le´ en pantalla,
ıdo

• se usar´ un vector intermedio de valores tipo int, de tama˜o fijo pero arbitrario.
a
n

Funciones para producir y consumir:

Para producir un item de datos, la hebra productora invocar´ esta funci´n:
a
o

§
int producir_dato()
{
static int contador = 1 ;
return contador ++ ;
}
¦

¤

¥

mientras que la hebra consumidora llama a esta otra para consumir un dato:

§
void consumir_dato( int dato )
{
cout << "dato recibido: " << dato << endl ;
}
¦

¤

¥

Hebras productora y consumidora

Los subprogramas que ejecutan las hebras productora y consumidora son como se indica a continuaci´n (no
o
se incluye la sincronizaci´n ni los accesos al vector):
o

§
void * productor( void * )
{
for( unsigned i = 0 ; i < num_items ; i++ )
{
int dato = producir_dato() ;
// falta: insertar ”dato” en el vector
}
return NULL ;
}
void * consumidor( void * )
{
for( unsigned i = 0 ; i < num_items ; i++ )
{
int dato ;
// falta: leer ”dato” desde el vector intermedio
consumir_dato( dato ) ;
}
return NULL ;
}
¦

¤

¥

Es necesario definir la constante num items con alg´n valor concreto (entre 50 y 100 es adecuado)
u

Gesti´n de la ocupaci´n del vector intermedio
o
o

El vector intermedio (buffer) tiene una capacidad (n´mero de celdas usables) fija prestablecidada en una
u
constante del programa que llamamos, por ejemplo, tam_vec.
creado October 4, 2013- p´gina 173 / 222
a
SCD (13-14). Pr´ctica 1. Sincronizaci´n de hebras con sem´foros..
a
o
a

• La constente tam_vec deber´ ser estrictamente menor que num_items (entre 10 y 20 ser´ adecuado).
a
ıa

• En cualquier instante de la ejecuci´n, el n´mero de celdas ocupadas en el vector (por items de datos
o
u
producidos pero pendientes de leer) es un n´mero entre 0 (el buffer estar´ vac´ y tam_vec (el buffer
u
ıa
ıo)
estar´ lleno).
ıa

• Adem´s del vector, es necesario usar alguna o algunas variables adicionales que reflejen el estado de
a
ocupaci´n de dicho vector.
o

• Es necesario estudiar si el acceso a dicha variable o variables requiere o no requiere sincronizaci´n
o
alguna entre el productor y el consumidor.

Soluciones para la gesti´n de la ocupaci´n
o
o

Hay b´sicamente dos alternativas posibles para gestionar la ocupaci´n, se detallan aqu´
a
o
ı:
• LIFO (pila acotada), se usa una unica variable entera no negativa:
´

◾ primera_libre = ´
ındice en el vector de la primera celda libre (inicialmente 0). Esta variable
se incrementa al escribir, y se decrementa al leer.

• FIFO (cola circular), se usan dos variables enteras no negativas:

◾ primera_ocupada = ´
ındice en el vector de la primera celda ocupada (inicialmente 0). Esta
variable se incrementa al leer (m´dulo tam_vector).
o

◾ primera_libre = ´
ındice en el vector de la primera celda libre (inicialmente 0). Esta variable se
incrementa al escribir (m´dulo tam_vector).
o

(asumismos que los ´
ındices del vector van desde 0 hasta tam_vector-1, ambos incluidos)

7.2.3

Actividades y documentaci´n
o

Lista de actividades

Debes realizar las siguientes actividades en el orden indicado:

1. Dise˜a una soluci´n que permita conocer qu´ entradas del vector est´n ocupadas y qu´ entradas est´n
n
o
e
a
e
a
libres (usa alguna de las dos opciones dadas).
2. Dise˜a una soluci´n, mediante sem´foros, que permita realizar las esperas necesarias para cumplir los
n
o
a
requisitos descritos.

3. Implementa la soluci´n descrita en un programa C/C++ con hebras y sem´foros POSIX, completando
o
a
las plantillas incluidas en este gui´n. Ten en cuenta que el programa debe escribir la palabra fin
o
cuando hayan terminado las dos hebras.
4. Comprueba que tu programa es correcto: verifica que cada n´mero natural producido es consumido
u
exactamente una vez.

creado October 4, 2013- p´gina 174 / 222
a
SCD (13-14). Pr´ctica 1. Sincronizaci´n de hebras con sem´foros..
a
o
a
Documentaci´n a incluir dentro del portafolios
o

Se incorporar´ al portafolios un documento indicando la siguiente informaci´n:
a
o

1. Describe la variable o variables necesarias, y c´mo se determina en qu´ posici´n se puede escribir y
o
e
o
en qu´ posici´n se puede leer.
e
o
2. Describe los sem´foros necesarios, la utilidad de los mismos, el valor inicial y en qu´ puntos del
a
e
programa se debe usar sem wait y sem signal sobre ellos.

3. Incluye el c´digo fuente completo de la soluci´n adoptada.
o
o

7.3

7.3.1

El problema de los fumadores.
Descripci´n del problema.
o

Descripci´n del problema (1)
o

En este apartado se intenta resolver un problema algo m´s complejo usando hebras y sem´foros POSIX.
a
a
Considerar un estanco en el que hay tres fumadores y un estanquero.

1.1. Cada fumador representa una hebra que realiza una actividad (fumar), invocando a una funci´n fumar(),
o
en un bucle infinito.

1.2. Cada fumador debe esperar antes de fumar a que se den ciertas condiciones (tener suministros para
fumar), que dependen de la actividad del proceso que representa al estanquero.

1.3. El estanquero produce suministros para que los fumadores puedan fumar, tambi´n en un bucle infinito.
e

1.4. Para asegurar concurrencia real, es importante tener en cuenta que la soluci´n dise˜ada debe permitir
o
n
que varios fumadores fumen simult´neamente.
a

Descripci´n del problema (2)
o

A continuaci´n se describen los requisitos para que los fumadores puedan fumar y el funcionamiento del
o
proceso estanquero:

2.1. Antes de fumar es necesario liar un cigarro, para ello el fumador necesita tres ingredientes: tabaco,
papel y cerillas.

2.2. Uno de los fumadores tiene solamente papel, otro tiene solamente tabaco, y el otro tiene solamente
cerillas.
2.3. El estanquero coloca aleatoriamente dos ingredientes diferentes de los tres que se necesitan para
hacer un cigarro, desbloquea al fumador que tiene el tercer ingrediente y despu´s se bloquea.
e
2.4. El fumador desbloqueado toma los dos ingredientes del mostrador, desbloquea al estanquero para que
pueda seguir sirviendo ingredientes y fuma durante un tiempo despu´s de liarse el cigarro.
e

2.5. El estanquero, cuando se desbloquea, vuelve a poner dos ingredientes aleatorios en el mostrador, y se
repite el ciclo.

creado October 4, 2013- p´gina 175 / 222
a
SCD (13-14). Seminario 2. Hebras en Java..

7.3.2

Plantillas de c´digo
o

Simulaci´n de la acci´n de fumar
o
o

Para simular la acci´n de fumar, fumar(), se puede usar la funci´n unsigned sleep(unsigned segundos) que
o
o
suspende a la hebra que la invoca tantos segundos como indica su unico argumento. Para que el retardo
´
sea aleatorio, se puede tomar como referencia el siguiente fragmento c´digo:
o

§
#include <time.h>
// incluye ”time(....)”
#include <unistd.h> // incluye ”sleep(....)”
#include <stdlib.h> // incluye ”rand(...)”

¤

// funci´n que simula la acci´n de fumar
o
o
// como un retardo aleatorio de la hebra
void fumar() { sleep( rand() % 5 ); }

// ......
int main()
{
srand ( time(NULL) ); // inicializa la semilla aleatoria
// ....
}
¦

7.3.3

¥

Actividades y documentaci´n.
o

Dise˜o de la soluci´n
n
o

Dise˜a e implementa una soluci´n al problema en C/C++ usando cuatro hebras y los sem´foros necesarios.
n
o
a
La soluci´n debe cumplir los requisitos incluidos en la descripci´n, y adem´s debe:
o
o
a
• Evitar interbloqueos entre las distintas hebras.

• Producir mensajes en la salida est´ndar que permitan hacer un seguimiento de la actividad de las
a
hebras:
◾ El estanquero debe indicar cu´ndo produce suministros y qu´ suministros produce. Para esa
e
tablecer los ingredientes concretos (o directamente el fumador que podr´ usarlos), se debe usar
ıa
tambi´n la funci´n rand().
e
o

◾ Cada fumador debe indicar cu´ndo espera, qu´ producto o productos espera, y cu´ndo comienza
a
e
a
y finaliza de fumar.

Documentaci´n a incluir dentro del portafolios
o

Se incorporar´ al portafolios un documento incluyendo los siguientes puntos:
a
1. Sem´foros necesarios para sincronizaci´n y para cada uno de ellos:
a
o
• Utilidad.

• Valor inicial.

• Hebras que hacen sem wait y sem signal sobre dicho sem´foro.
a

creado October 4, 2013- p´gina 176 / 222
a
SCD (13-14). Seminario 2. Hebras en Java..

2. C´digo fuente completo de la soluci´n adoptada.
o
o

creado October 4, 2013- p´gina 177 / 222
a
SCD (13-14). Seminario 2. Hebras en Java..

creado October 4, 2013- p´gina 178 / 222
a
Chapter 8

Seminario 2. Hebras en Java.
Introducci´n
o

Este seminario es una breve introducci´n a la programaci´n con hebras en el lenguaje Java.
o
o

• El objetivo es conocer las principales formas de crear y gestionar y hebras en Java, con objeto de
desarrollar los ejemplos de la pr´ctica 2.
a

• Se mostrar´n las distintas formas de crear hebras en Java, los distintos estados de una hebra Java y
a
c´mo controlar la prioridad de las hebras.
o

• Se ver´ un mecanismo para asegurar la exclusi´n mutua en el acceso concurrente a bloques de c´digo
a
o
o
Java.

Enlaces para acceder a informaci´n complementaria
o
• Aprenda Java como si Estuviera en primero.
• Tutorial de Java.
• Manual de Java.

• Informaci´n sobre la clase Thread.
o

179
SCD (13-14). Seminario 2. Hebras en Java..

8.1

Hebras en Java

Concepto de hebra en Java

• La mayor´ de las implementaciones de Java incluyen un compilador que genera c´digo intermedio
ıa
o
independiente de la m´quina (llamado bytecode) m´s un int´rprete de dicho c´digo intermedio.
a
a
e
o
• El bytecode es interpretado por un proceso denominado M´quina Virtual Java (JVM).
a

• Las hebras Java se ejecutan dentro de la JVM y comparten los recursos de este proceso del sistema
operativo.
• Java ofrece una interfaz para manejar hebras.

• Una hebra Java es una instancia de una clase que implementa la interfaz Runnable, y/o instancias
de una subclase de la clase Thread.

• Los m´todos de las clases Thread y Object (definidas en el paquete java.lang) son los que
e
hacen posible la gesti´n y sincronizaci´n de hebras en Java.
o
o

Ejecuci´n de una hebra en Java
o

a) Por defecto, al ejecutar un programa Java, tenemos una hebra asociada al m´todo main(), que va
e
recorriendo distintos objetos conforme se invocan los correspondientes m´todos.
e

b) Dentro de la hebra main, se pueden crear varias hebras que pueden ejecutar m´todos del mismo o de
e
diferentes objetos en el mismo o en diferente momento.
a)

8.2

b)

Creaci´n de hebras en Java
o

Creaci´n de hebras en Java
o

Para ejecutar una hebra en Java es necesario definir (al menos) una clase C que contenga un m´todo run.
e
Cada hebra ejecuta el c´digo de dicho m´todo para una instancia de C. Esto se puede implementar de dos
o
e
formas:
creado October 4, 2013- p´gina 180 / 222
a
SCD (13-14). Seminario 2. Hebras en Java..

• C es una clase derivada de la clase Thread:

◾ Thread es una clase predefinida en el lenguaje.

◾ Se impide que C sea derivada de otra clase distinta de Thread.

• C es una clase que implementa la interfaz Runnable:

◾ Runnable es un interfaz predefinido en el lenguaje.

◾ C puede extender (ser derivada de) una clase base cualquiera.

◾ Se requiere adicionalmente la creaci´n de una instancia de Thread por cada hebra a ejecutar.
o
Esta instancia guarda una referencia a la instancia de C.

Nosotros usaremos la segunda opci´n precisamente por su mayor flexibilidad, a pesar de que es ligeramente
o
m´s complejo. Habr´ tantas clases C como sea necesario.
a
a
Uso de Runnable y Thread

Por cada hebra a ejecutar es necesario crear, adem´s de una instancia r de C, una instancia t de Thread (t
a
contiene una referencia a r). Hay dos posibilidades:
• El objeto r y despu´s t se crean de forma independiente en la aplicaci´n como dos objetos distintos.
e
o

• La clase C incluye como variable de instancia el objeto t (el objeto r tiene una referencia a t, o bien
decimos que el objeto Runnable encapsula al objeto Thread).

nosotros usaremos la segunda opci´n ya que fuera del c´digo de C solo tendremos que gestionar un objeto
o
o
C en lugar de dos de ellos (uno C y otro Thread).
Creaci´n y ejecuci´n de una hebra.
o
o

Definiremos una clase TipoHebra, la cual

• puede ser derivada de una clase base Base cualquiera (no es necesario).

• tiene una variable de instancia p´blica de nombre, por ejemplo, thr, de la clase Thread.
u
• en su constructor crea el objeto thr.

Para ejecutar una de estas hebras es necesario:

1. Declarar una instancia obj de la clase TipoHebra (internamente se crea obj.thr).

2. Usar el m´todo start de Thread sobre obj.thr, es decir, ejecutar obj.thr.start().
e

La nueva hebra comienza la ejecuci´n concurrente de obj.run().
o

creado October 4, 2013- p´gina 181 / 222
a
SCD (13-14). Seminario 2. Hebras en Java..
Ejemplo de una hebra

La definici´n de TipoHebra puede, a modo de ejemplo, ser as´
o
ı:
§
class TipoHebra implements Runnable // opcionalmente: extends ....
{
long siesta ;
// tiempo que duerme la hebra
public Thread thr ; // objeto hebra encapsulado

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21 }
¦

¤

public TipoHebra( String nombre, long siesta )
{ this.siesta = siesta;
thr = new Thread( this, nombre );
}
public void run()
{ try
{ while ( true )
{ System.out.println( "Hola, soy "+thr.getName() );
if ( siesta > 0 ) Thread.sleep( siesta );
}
}
catch ( InterruptedException e )
{ System.out.println( "me fastidiaron la siesta!" );
}
}
¥

Programa principal

Lanza una hebra y despu´s hace join (la espera) y getName.
e
§
class Principal1
{
public static void main( String[] args ) throws InterruptedException
{
if ( args.length < 1 )
{ System.out.println( "Error: falta valor de ’siesta’" );
System.exit(1);
}
long siesta = Long.parseLong( args[0] ) ;
TipoHebra obj = new TipoHebra("hebra ’obj’", siesta); // crear hebra

23
24
25
26
27
28
29
30
31
32
33
34
obj.thr.start();
// lanzar hebra
35
Thread.sleep( 100 ); // la hebra principal duerme 1/10 sec.
36
obj.thr.join();
// esperar a que termine la hebra
37
}
38 }
¦

8.3

Estados de una hebra Java

Estados de una hebra Java

creado October 4, 2013- p´gina 182 / 222
a

¤

¥
SCD (13-14). Seminario 2. Hebras en Java..

• Nueva: Cuando el objeto hebra es creado, por ejemplo con:
§
¦

Thread thr = new Thread (a);

• Ejecutable: Cuando se invoca al m´todo start de una nueva hebra:
e
§
¦

thr.start ();

• En ejecuci´n: Cuando la hebra est´ ejecut´ndose en alguna CPU del computador. Si una hebra en
o
a
a
este estado ejecuta el m´todo yield, deja la CPU y pasa el estado ejecutable:
e
§
¦

Thread.yield ();

// metodo static de la clase Thread

• Bloqueada: Una hebra pasa a este estado:

◾ cuando llama al m´todo sleep, volviendo al estado ejecutable cuando retorne la llamada:
e
§
¦

Thread.sleep (tiempo_milisegundos}; // metodo est´tico
a

◾ cuando llama a wait dentro de un bloque o un m´todo sincronizado, volviendo al estado ejecutable
e
cuando otra hebra llame a notify o a notifyAll
◾ cuando llama a join para sincronizarse con la terminaci´n de otra hebra que a´n no ha terminado:
o
u
§

¤
¥
¤
¥

¤
¥

¤
¥

¤

thr.join ();

¦

◾ cuando ejecuta alguna operaci´n de e/s bloqueante.
o

• Muerta: Cuando su m´todo run termina.
e

Transiciones entre estados

El siguiente diagrama muestra de forma resumida las diferentes transiciones entre estados y los m´todos
e
que los provocan:

creado October 4, 2013- p´gina 183 / 222
a

¥
SCD (13-14). Seminario 2. Hebras en Java..

8.4

Prioridades y planificaci´n.
o

Prioridad de una hebra

• Cada hebra tiene una prioridad que afecta a su planificaci´n. Una hebra hereda la prioridad de la hebra
o
que la cre´. La prioridad es un valor entero entre Thread.MIN_PRIORITY y Thread.MAX_PRIORITY
o
(dos constantes).

• La prioridad actual de una hebra puede obtenerse invocando el m´todo getPriority, y se modifica
e
con setPriority. En el ejemplo creamos una hebra y decrementamos su prioridad antes de llamar a
start:
§

¦

thr = new Thread( obj );
thr.setPriority( thr.getPriority()-1 );
thr.start();

¤

¥

Planificaci´n de hebras
o

• El planificador de hebras de Java asegura que la hebra ejecutable con mayor prioridad (o una de ellas,
si hay varias) pueda ejecutarse en la CPU. Si una hebra con mayor prioridad que la actual pasa a
estar en estado ejecutable, la hebra actual pasa al estado ejecutable, y la hebra ejecutable de mayor
prioridad es ejecutada (se apropia de la CPU).

• Si la hebra actual invoca a yield, se suspende, o se bloquea, el planificador elige para ejecuci´n la
o
pr´xima hebra de mayor prioridad.
o

• Otro aspecto de la planificaci´n es el tiempo compartido, es decir la alternancia en el uso de la CPU
o
por parte de las hebras ejecutables de mayor prioridad.

8.4.1

Un ejemplo m´s completo
a

Ejemplo de un vector de hebras.

El este ejemplo se crea un array de hebras de acuerdo con el esquema visto en la primera secci´n. Cada
o
hebra es una instancia de Dormilona:

§
44 class Dormilona implements Runnable
45 {
46
int vueltas = 0 ; // n´mero de veces que duerme (0 == infinitas)
u
47
int siesta = 0 ; // tiempo m´ximo que duerme cada vez
a
48
public Thread thr ; // objeto hebra encapsulado
49
50
public Dormilona( String p_nombre, int p_vueltas, int p_siesta )
51
{
52
siesta = p_siesta ;
53
vueltas = p_vueltas ;
54
thr
= new Thread( this, p_nombre ) ;
55
}
56
57
//...
¦

creado October 4, 2013- p´gina 184 / 222
a

¤

¥
SCD (13-14). Seminario 2. Hebras en Java..
Ejemplo de un vector de hebras (2)

El m´todo run contiene el c´digo que ejecutan todas las hebras:
e
o

§

58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76 }
¦

79
80
81
82
83
84
85
86
87
88
89
90
91
92
93

94
95
96
97

//...
public void run()
{ try
{ Random random = new Random(); // crea generador de n´meros aleatorios
u
// dormir un numero de veces igual a ”vueltas”
for ( int i=0 ; i < vueltas || vueltas == 0 ; i++ )
{ // imprimir nombre
System.out.println( "Vuelta no."+i+", de " +thr.getName());
// duerme un tiempo aleatorio entre 0 y siesta-1 milisegundos
if ( siesta > 0 )
Thread.sleep( random.nextInt( siesta ) );
}
}
catch( InterruptedException e )
{ System.out.println( Thread.currentThread().getName()+
": me fastidiaron la siesta!");
}
} // fin run
// fin de la clase Dormilona

Ejemplo de un vector de hebras (4)
El m´todo main lee los par´metros.
e
a

§
class Principal2
{
public static void main( String[] args )
{ try
{ if ( args.length < 3 )
{ System.out.println( "falta num_hebras, t_max_siesta, vueltas" );
System.exit( 1 );
}
int nHebras = Integer.parseInt( args[0] );
int siesta = Integer.parseInt( args[1] );
int vueltas = Integer.parseInt( args[2] );

¦

System.out.println( "nHebras = "+nHebras+", vueltas = "+vueltas+
", tsiesta = "+siesta );
//....

Ejemplo de un vector de hebras (5)

Finalmente, se crean las hebras en el vector vhd y se lanzan todas

§

//....

Dormilona[] vhd = new Dormilona[nHebras] ; // crea vector de hebras

creado October 4, 2013- p´gina 185 / 222
a

¤

¥

¤

¥

¤
SCD (13-14). Seminario 2. Hebras en Java..

98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
}
115 }
¦

for ( int i =0 ; i < nHebras ; i++ )
{ String nombre = "Dormilona no."+i ;
vhd[i] = new Dormilona(nombre,vueltas,siesta); // crear hebra i.
vhd[i].thr.start();
// comienza su ejec.
}
// la hebra principal duerme durante un segundo
Thread.sleep( 1000 );
System.out.println( "main(): he terminado de dormir" );
// esperar a que terminen todas las hebras creadas
for( int i = 0 ; i < nHebras ; i++ )
vhd[i].thr.join();

}
catch( InterruptedException e )
{ System.out.println( "main(): me fastidiaron la siesta!" );
}

8.5

¥

Interacci´n entre hebras Java. Objetos compartidos
o

Interacci´n entre hebras Java. Objetos compartidos
o

• En muchos casos, las hebras de un programa concurrente en Java han de interactuar para comunicarse
y cooperar.

• La forma m´s simple en la que m´ltiples hebras Java pueden interactuar es mediante un objeto cuyos
a
u
m´todos pueden ser invocados por un conjunto de hebras. Invocando los m´todos de este objeto
e
e
compartido las hebras modifican el estado del mismo.
• Dos hebras se pueden comunicar si una escribe el estado del objeto compartido y otra lo lee. Asimismo,
la cooperaci´n entre hebras se puede llevar a cabo mediante la actualizaci´n de alguna informaci´n
o
o
o
encapsulada en un objeto compartido.
• La ejecuci´n concurrente entre hebras Java supone un entrelazamiento arbitrario de instrucciones
o
at´micas que puede dar lugar a estados incorrectos de los objetos compartidos por varias hebras.
o

8.5.1

Implementando exclusi´n mutua en Java. C´digo y m´todos sincronizados.
o
o
e

Exclusi´n mutua en Java. C´digo y m´todos sincronizados.
o
o
e

• En Java, cda objeto tiene un cerrojo interno asociado. El cerrojo de un objeto solamente puede ser
adquirido por una sola hebra en cada momento.
• El cualificador synchronized sirve para hacer que un bloque de c´digo o un m´todo sea protegido
o
e
por el cerrojo del objeto.

creado October 4, 2013- p´gina 186 / 222
a
SCD (13-14). Seminario 2. Hebras en Java..

• Para ejecutar un bloque o un m´todo sincronizado, las hebras deben adquirir el cerrojo del objeto,
e
debiendo esperar si el cerrojo ha sido ya adquirido por otra hebra.

• Si obj es una referencia a un objeto (de cualquier clase), la siguiente construcci´n hace que las hebras
o
tengan que adquirir el cerrojo del objeto para ejecutar el bloque de c´digo sincronizado.
o
§

¦

synchronized( obj )
{
// bloque de codigo sincronizado
}

¥

Si todas las secciones cr´
ıticas est´n en el c´digo de un unico objeto, podremos utilizar this para referenciar
a
o
´
al objeto cuyo cerrojo vamos a utilizar:

§

¦

synchronized( this )
{ // bloque de codigo sincronizado
}

Podemos hacer que el cuerpo entero de un m´todo sea c´digo sincronizado:
e
o
tipo metodo( ... )
{ synchronized( this )
{ // codigo del metodo sincronizado
}
}

La siguiente construcci´n es equivalente a la anterior:
o

¤

synchronized tipo metodo( ... )
{ // codigo del metodo sincronizado
}

8.5.2

¤

¥

§

¦

¤

¥

§

¦

¤

¥

Ejemplo: C´lculo de m´ltiplos
a
u

Clase contador de n´mero de m´ltiplos
u
u

Programa multihebra para calcular el n´mero de m´ltiplos de 2 y 3 entre 1 y 1000 ambos incluidos.
u
u
• Una hebra contar´ m´ltiplos de 2 y otra de 3.
a u

• Para llevar la cuenta se crea un unico objeto compartido de la clase Contador, que encapsula un valor
´
entero.
• La clase Contador incluye un m´todo para incrementarlo y otro para obtener el valor.
e
• El uso compartido requiere usar esas m´todos en exclusi´n mutua.
e
o

creado October 4, 2013- p´gina 187 / 222
a
SCD (13-14). Seminario 2. Hebras en Java..
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19

Clase contador de n´mero de m´ltiplos
u
u

La clase Contador puede declararse as´
ı:
§
class Contador
{ private long valor;
public Contador( long inicial )
{ valor = inicial ;
}
void retrasoOcupado() // ocupa la CPU durante cierto tiempo
{ long tmp = 0 ;
for( int i = 0 ; i < 100000 ; i++ )
tmp = tmp*i-tmp+i ;
}
public synchronized void incrementa () // incrementa valor en 1
{ long aux = valor ; // hace copia local del valor actual
retrasoOcupado() ; // permite entrelazado cuando no se hace en EM
valor = aux+1 ;
// escribe el valor compartido (incrementado)
}
public synchronized long getvalor () // devuelve el valor actual
{ return valor;
}
}
¦
Hebras que cuentan los m´ltiplos
u

Cada una de las hebras incrementa el contador cuando encuentra un m´ltiplo:
u

§
class Hebra implements Runnable
{ int numero ;
// cuenta m´ltiplos de este n´mero
u
u
public Thread thr ;
// objeto encapsulado
private Contador cont;
// contador de n´mero de m´ltiplos
u
u

21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36 }
¦

¤

¥

¤

public Hebra( String nombre, int p_numero, Contador p_contador )
{ numero = p_numero;
cont
= p_contador;
thr = new Thread( this, nombre );
}
public void run ()
{ for ( int i = 1 ; i <= 1000 ; i++ )
if (i % numero == 0)
cont.incrementa();
}
¥

¿ que pasar´ si los dos m´todos de Contador no fueran synchronized ?
ıa
e
Programa principal

Lanza dos hebras e imprime la cuenta calculada y la correcta:

§
38 class Multiplos
39 { public static void main( String[] args )

¤

creado October 4, 2013- p´gina 188 / 222
a
SCD (13-14). Seminario 2. Hebras en Java..

40
{ try
41
{ Contador contH = new Contador(0); // contador usado por la hebras
42
Hebra[] vc = new Hebra[2] ;
43
vc[0] = new Hebra( "Contador2 ", 2, contH);
44
vc[1] = new Hebra( "Contador3 ", 3, contH);
45
vc[0].thr.start(); vc[1].thr.start(); // lanza hebras
46
vc[0].thr.join(); vc[1].thr.join(); // espera terminaci´n
o
47
System.out.println("Resultado hebras : "+contH.getvalor());
48
long contV = 0 ; // contador de verificacion
49
for ( int i = 1 ; i <= 1000 ; i++ )
50
{ if ( i % 2 == 0 ) contV = contV + 1 ;
51
if ( i % 3 == 0 ) contV = contV + 1 ;
52
}
53
System.out.println("Resultado correcto: " + contV);
54
}
55
catch (InterruptedException e)
56
{ System.out.println ("ha ocurrido una excepcion.");
57
}
58
}
59 }
¦

8.6

¥

Compilando y ejecutando programas Java

Compilar programas Java

Los programas fuente se encuentran en archivos de extensi´n .java. Cada uno de ellos contendr´ una o
o
a
mas definiciones de clases. Para compilar un fuente java (en un archivo principal.java, por ejemplo),
hay que escribir:

§

javac principal.java

¦

Si el programa principal hace menci´n a clases definidas en otros archivos, el compilador intentar´
o
a
compilarlos tambi´n, aunque se podr´ hacer manualmente antes:
e
ıa

§

javac otro1.java
javac otro2.java
javac ....

¦

¤
¥

¤

¥

esto generar´ un archivo objeto (con bytecode) por cada clase definida en principal.java o en los otros
a
archivos.
Ejecutar programas Java

Los archivos con bytecode tienen el nombre de la clase y la extensi´n .class.
o

Una de las clases compiladas debe contener el m´todo principal (main), y lo usual (aunque no necesario)
e
es que dicha clase se llame igual que el fuente que lo contiene (en este caso principal). Si esto ocurre,
el programa se ejecuta con la orden:

§

java principal

¦

creado October 4, 2013- p´gina 189 / 222
a

¤
¥
SCD (13-14). Pr´ctica 2. Programaci´n de monitores con hebras Java..
a
o

para poder encontrar los archivos binarios javac y java hay que asignar la variable de entorno PATH, en
las aulas:

§

export PATH=/fenix/depar/lsi/java/jdk1.5.0linux/bin:.:${PATH}

¦

creado October 4, 2013- p´gina 190 / 222
a

¤
¥
Chapter 9

Pr´ctica 2. Programaci´n de monitores con
a
o
hebras Java.
9.1

Objetivos

Objetivos

• Conocer c´mo construir monitores en Java, tanto usando la API para manejo de hebras Java, como
o
usando un conjunto de clases (el paquete monitor) que permite programar monitores siguiendo la
misma sem´ntica de los monitores de Hoare.
a
• Conocer varios problemas sencillos de sincronizaci´n y su soluci´n basada en monitores en el lenguaje
o
o
Java:

◾ Dise˜ar una soluci´n al problema del productor-consumidor con buffer acotado basada en monin
o
tores e implementarla con un programa Java multihebra, usando el paquete monitor.
◾ Dise˜ar una soluci´n al problema de los fumadores, visto en la pr´ctica 1, basada en monitores
n
o
a
e implementarla con un programa Java multihebra, usando el paquete monitor.

9.2

9.2.1

◾ Dise˜ar e implementar una soluci´n al problema del barbero durmiente usando el paquete
n
o
monitor.

Implementaci´n de monitores nativos de Java
o
Monitores como Clases en Java

Monitores como Clases en Java

Para construir un monitor en Java, creamos una clase con sus m´todos sincronizados. De esta forma solamente
e
una hebra podr´ ejecutar en cada momento un m´todo del objeto.
a
e
El siguiente ejemplo muestra un monitor que implementa un contador m´s general que el visto en el seminario:
a

§

class Contador
{ private volatile int actual;

// monitor contador

191

¤
SCD (13-14). Pr´ctica 2. Programaci´n de monitores con hebras Java..
a
o
public Contador( int inicial )
{ actual = inicial ;
}
public synchronized void inc()
{ actual++ ;
}
public synchronized void dec()
{ actual-- ;
}
public synchronized int valor()
{ return actual ;
}

¦

}

9.2.2

¥

M´todos de espera y notificaci´n.
e
o

M´todos de espera y notificaci´n (1)
e
o

• En Java no existe el concepto de variable condici´n. Podr´
o
ıamos decir que cada monitor en Java tiene
una unica variable condici´n an´nima.
´
o
o

• Los monitores basados en la biblioteca est´ndar de Java implementan una versi´n restringida de la
a
o
sem´ntica Se˜alar y Continuar (SC).
a
n

• Los mecanismos de espera y notificaci´n se realizan con tres m´todos de la clase Object (los tienen
o
e
impl´
ıcitamente todas las clases): wait, notify y notifyAll.

• Estos m´todos solamente pueden ser llamados por una hebra cuando ´sta posee el cerrojo del objeto,
e
e
es decir, desde un bloque o un m´todo sincronizado (protegido con synchronized).
e

M´todos de espera y notificaci´n (2)
e
o
wait()

Provoca que la hebra actual se bloquee y sea colocada en una cola de espera asociada al objeto monitor.
El cerrojo del objeto es liberado para que otras hebras puedan ejecutar m´todos del objeto. Otros cerrojos
e
pose´
ıdos por la hebra suspendida son retenidos por esta.
notify()

Provoca que, si hay alguna hebra bloqueada en wait, se escoja una cualquiera de forma arbitraria, y se saque
de la cola de wait pasando esta al estado preparado. La hebra que invoc´ notify seguir´ ejecut´ndose
o
a
a
dentro del monitor.
notifyAll()

Produce el mismo resultado que una llamada a notify por cada hebra bloqueada en la cola de wait: todas
las hebras bloqueadas pasan al estado preparado.
creado October 4, 2013- p´gina 192 / 222
a
SCD (13-14). Pr´ctica 2. Programaci´n de monitores con hebras Java..
a
o
M´todos de espera y notificaci´n (3)
e
o

La hebra se˜alada deber´ adquirir el cerrojo del objeto para poder ejecutarse.
n
a

• Esto significar´ esperar al menos hasta que la hebra que invoc´ notify libere el cerrojo, bien por la
a
o
ejecuci´n de una llamada a wait, o bien por la salida del monitor.
o

La hebra se˜alada no tiene prioridad alguna para ejecutarse en el monitor.
n

• Podr´ ocurrir que, antes de que la hebra se˜alada pueda volver a ejecutarse, otra hebra adquiera el
ıa
n
cerrojo del monitor.

Inconvenientes de los monitores nativos de Java

• Cola de espera ´nica: como s´lo hay una cola de espera por objeto, todas las hebras que esperan a
u
o
que se den diferentes condiciones deben esperar en el mismo conjunto de espera. Esto permite que
una llamada a notify() despierte a una hebra que espera una condici´n diferente a la que realmente
o
se notific´, incluso aunque existan hebras esperando la condici´n que realmente se pretend´ notificar.
o
o
ıa
La soluci´n para esta restricci´n suele consistir en:
o
o
◾ Sustituir algunas o todas las llamadas a notify por llamadas a notifyAll.
◾ Poner las llamadas a wait en un bucle de espera activa:
§
while ( not
¦

condicion_logica_desbloqueo ) { wait() ; }

¤
¥

• No hay reanudaci´n inmediata de hebra se˜alada: esto se debe a la sem´ntica SC que se sigue y
o
n
a
es la segunda raz´n del uso de incluir las llamadas a wait en bucles de espera activa.
o

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20

Ejemplo: Productor-Consumidor con buffer limitado

Monitor que implementa un buffer acotado para m´ltiples productores y consumidores:
u

§
class Buffer
{ private int numSlots = 0, cont = 0;
private double[] buffer = null;
public Buffer( int p_numSlots )
{ numSlots = p_numSlots ;
buffer = new double[numSlots] ;
}
public synchronized void depositar( double valor ) throws InterruptedException
{ while( cont == numSlots ) wait();
buffer[cont] = valor; cont++;
notifyAll();
}
public synchronized double extraer() throws InterruptedException
{ double valor;
while( cont == 0 ) wait() ;
cont--; valor = buffer[cont] ;
notifyAll();
return valor;
}
}
¦

creado October 4, 2013- p´gina 193 / 222
a

¤

¥
SCD (13-14). Pr´ctica 2. Programaci´n de monitores con hebras Java..
a
o
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44

Productor-Consumidor: hebras consumidoras

§
class Consumidor implements Runnable
{ private Buffer bb ;
int veces;
int numC ;
Thread thr ;
public Consumidor( Buffer pbb, int pveces, int pnumC )
{ bb
= pbb;
veces = pveces;
numC = pnumC ;
thr
= new Thread(this,"consumidor "+numC);
}
public void run()
{ try
{ for( int i=0 ; i<veces ; i++ )
{ double item = bb.extraer ();
System.out.println(thr.getName()+", consumiendo "+item);
}
}
catch( Exception e )
{ System.err.println("Excepcion en main: " + e);
}
}
}
¦

Productor-Consumidor: hebras productoras

§
class Productor implements Runnable
{ private Buffer bb ;
int veces;
int numP ;
Thread thr ;
public Productor( Buffer pbb, int pveces, int pnumP )
{ bb
= pbb;
veces = pveces;
numP = pnumP ;
thr
= new Thread(this,"productor "+numP);
}
public void run()
{ try
{ double item = 100*numP ;
for( int i=0 ; i<veces ; i++ )
{ System.out.println(thr.getName()+", produciendo " + item);
bb.depositar( item++ );
}
}
catch( Exception e )
{ System.err.println("Excepcion en main: " + e);
}
}

creado October 4, 2013- p´gina 194 / 222
a

¤

¥

¤
SCD (13-14). Pr´ctica 2. Programaci´n de monitores con hebras Java..
a
o

45 }
¦

¥

9.3

Implementaci´n en Java de monitores estilo Hoare
o

Implementaci´n en Java de monitores estilo Hoare
o

• Se ha desarrollado una biblioteca de clases Java (paquete monitor) que soporta la sem´ntica de
a
monitores estilo Hoare.

• Permite definir m´ltiples colas de condici´n y un signal supone la reactivaci´n inmediata del proceso
u
o
o
se˜alado (sem´ntica Se˜alar y espera Urgente, SU).
n
a
n
• La documentaci´n y el c´digo de las clases est´n disponibles en:
o
o
a
http://www.engr.mun.ca/ theo/Misc/monitors/monitors.html

• Para definir una clase monitor espec´
ıfica se debe definir una extensi´n de la clase AbstractMonitor.
o

Exclusi´n mutua y uso del paquete monitor
o

Para garantizar la exclusi´n mutua en el acceso a los m´todos del monitor, se han de invocar los siguientes
o
e
m´todos de la clase AbstractMonitor:
e
• enter(): para entrar al monitor, se invoca al comienzo del cuerpo del m´todo.
e

• leave(): para abandonar el monitor, se invoca al final del cuerpo (aunque cualquier return debe ir
despu´s).
e

Uso del paquete

• Es conveniente que el directorio monitor, conteniendo los archivos .java con las clases Java de dicho
paquete, se encuentre colgando del mismo directorio donde se trabaje con los programas Java que usen
el paquete monitor.

• En caso contrario, habr´ que redefinir la variable de entorno CLASSPATH incluyendo la ruta de dicho
ıa
directorio.

Ejemplo: Clase Monitor para contar los d´
ıas

3
4
5
6
7
8
9

Permite llevar un control de los d´ (considerados como grupos de 24 horas) dedicadas por todas las hebras
ıas
de usuario.

§
class Contador_Dias extends AbstractMonitor
{ private int num_horas = 0, num_dias = 0;
public void nueva_hora()
{ enter() ;
num_horas++;
if ( num_horas == 24 )
{ num_dias++;

creado October 4, 2013- p´gina 195 / 222
a

¤
SCD (13-14). Pr´ctica 2. Programaci´n de monitores con hebras Java..
a
o

10
11
12
13
14
15
16
17
18
19
20 }
¦

num_horas=0;
}
leave() ;

}
public int obtener_dia( )
{ enter() ;
int valor=num_dias;
leave() ;
return valor;
}
¥

Objetos condici´n del paquete monitor
o

Es posible utilizar varias colas de condici´n, declarando diversos objetos de una clase denominada Condition.
o
• Para crear un objeto condici´n, se invoca el m´todo makeCondition() de la clase AbstractMonitor.
o
e
Ejemplo:
§
¦

Condition puede_leer = makeCondition() ;

¤
¥

La clase Condition proporciona m´todos de espera, notificaci´n y para consultar el estado de la cola de
e
o
condici´n:
o
• void await(): tiene la misma sem´ntica que la primitiva wait() de los monitores estilo Hoare.
a
• void signal(): igual que la primitiva signal() de los monitores estilo Hoare.
• int

count(): devuelve el n´mero de hebras que esperan.
u

• boolean isEmpty(): indica si la cola de condici´n est´ vac´ (true) o no (false).
o
a
ıa

4
5
6
7
8
9
10
11
12
13
14
15
16
17
18

Ejemplo: Monitor lectores-escritores (1)
Con prioridad a las lecturas.

§
class MonitorLE extends AbstractMonitor
{
private int num_lectores = 0 ;
private boolean escribiendo = false ;
private Condition lectura
= makeCondition();
private Condition escritura = makeCondition();

¤

public void inicio_lectura()
{ enter();
if (escribiendo) lectura.await();
num_lectores++;
lectura.signal();
leave();
}
public void fin_lectura()

creado October 4, 2013- p´gina 196 / 222
a
19
20
21
22
23

SCD (13-14). Pr´ctica 2. Programaci´n de monitores con hebras Java..
a
o

¦

{ enter();
num_lectores--;
if (num_lectores==0) escritura.signal();
leave();
}

¥

Ejemplo: Monitor lectores-escritores (2)

§

24
25
26
27
28
29
30
31
32
33
34
35
36
37 }
¦

¤

public void inicio_escritura()
{ enter();
if (num_lectores>0 || escribiendo) escritura.await();
escribiendo=true;
leave();
}
public void fin_escritura() // prio. lect
{ enter();
escribiendo=false;
if (lectura.isEmpty()) escritura.signal();
else lectura.signal();
leave();
}
// fin clase monitor ”Lect Esc”

Probl. lectores-escritores: Hebra Lectora.

§
class Lector implements Runnable
{
private MonitorLE monitorLE ; // objeto monitor l.e. compartido
private int
nveces ; // numero de veces que lee
public Thread
thr
; // objeto hebra encapsulado

52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72 }
¦

¥

¤

public Lector( MonitorLE p_monitorLE, int p_nveces, String nombre )
{ monitorLE = p_monitorLE ;
nveces
= p_nveces ;
thr
= new Thread(this,nombre);
}
public void run()
{ for( int i = 0 ; i < nveces ; i++ )
{ System.out.println( thr.getName()+": solicita lectura.");
monitorLE.inicio_lectura();
System.out.println( thr.getName()+": leyendo.");
aux.dormir_max( 1000 ) ;
monitorLE.fin_lectura();
}
}

Probl. lectores-escritores: Hebra Escritora.

¥

creado October 4, 2013- p´gina 197 / 222
a
SCD (13-14). Pr´ctica 2. Programaci´n de monitores con hebras Java..
a
o

§
74 class Escritor implements Runnable
75 {
76
private MonitorLE monitorLE ; // objeto monitor l.e. compartido
77
private int
nveces ; // numero de veces que lee
78
public Thread
thr
; // objeto hebra encapsulado
79
80
public Escritor( MonitorLE p_monitorLE, int p_nveces, String nombre )
81
{ monitorLE = p_monitorLE ;
82
nveces
= p_nveces ;
83
thr
= new Thread(this,nombre);
84
}
85
public void run()
86
{ for( int i = 0 ; i < nveces ; i++ )
87
{ System.out.println( thr.getName()+": solicita escritura.");
88
monitorLE.inicio_escritura();
89
System.out.println( thr.getName()+": escribiendo.");
90
aux.dormir_max( 1000 );
91
monitorLE.fin_escritura ();
92
}
93
}
94 }
¦

¤

¥

Probl. lectores-escritores: clase auxiliar

se ha usado el m´todo (est´tico) dormir_max de la clase aux. Este m´todo sirve para bloquear la hebra
e
a
e
que lo llama durante un tiempo aleatorio entre 0 y el n´mero m´ximo de milisegundos que se le pasa como
u
a
par´metro. Se puede declarar como sigue:
a

§
39 class aux
40 {
41
static Random genAlea = new Random() ;
42
static void dormir_max( int milisecsMax )
43
{ try
44
{ Thread.sleep( genAlea.nextInt( milisecsMax ) ) ;
45
}
46
catch( InterruptedException e )
47
{ System.err.println("sleep interumpido en ’aux.dormir_max()’");
48
}
49
}
50 }
¦

9.4

Productor-Consumidor con buffer limitado

Ejercicio propuesto

Obtener una versi´n de la clase Buffer, que se desarroll´ en una secci´n anterior para m´ltiples productores
o
o
o
u
y consumidores, usando las clases vistas del paquete monitor.
Documentaci´n para el portafolio
o

creado October 4, 2013- p´gina 198 / 222
a

¤

¥
SCD (13-14). Pr´ctica 2. Programaci´n de monitores con hebras Java..
a
o

Los alumnos redactar´n un documento donde se responda de forma razonada a cada uno de los siguientes
a
puntos:

1. Describe los cambios que has realizado sobre la clase Buffer vista anteriormente, indicando qu´
e
objetos condici´n has usado y el prop´sito de cada uno.
o
o
2. Incluye el c´digo fuente completo de la soluci´n adoptada.
o
o

3. Incluye un listado de la salida del programa (para 2 productores, 2 consumidores, un buffer de tama˜o
n
3 y 5 iteraciones por hebra.

9.5

El problema de los fumadores

El problema de los fumadores

Considerar un estanco en el que hay tres fumadores y un estanquero. Cada fumador continuamente l´ un
ıa
cigarro y se lo fuma. Para liar un cigarro, el fumador necesita tres ingredientes: tabaco, papel y cerillas.
Uno de los fumadores tiene solamente papel, otro tiene solamente tabaco, y el otro tiene solamente cerillas.
El estanquero tiene una cantidad infinita de los tres ingredientes.
El estanquero coloca aleatoriamente dos ingredientes diferentes de los tres que se necesitan para hacer un
cigarro, desbloquea al fumador que tiene el tercer ingrediente y despu´s se bloquea. El fumador desbloe
queado toma los dos ingredientes del mostrador, desbloqueando al estanquero, l´ un cigarro y fuma durante
ıa
un tiempo. El estanquero, una vez desbloqueado, vuelve a poner dos ingredientes aleatorios en el mostrador,
y se repite el ciclo.
Ejercicio propuesto

Escribir un programa Java que implemente el esquema de sincronizaci´n explicado. Se escribir´ una clase
o
a
hebra Estanquero y otra Fumador, especificando en el constructor de esta ultima clase el ingrediente que
´
tiene el fumador. La interacci´n entre los fumadores y el estanquero ser´ resuelta mediante un monitor
o
a
Estanco basado en el paquete monitor. Usar las plantillas que se incluyen abajo.

Documentaci´n a entregar
o

Los alumnos redactar´n un documento donde se responda de forma razonada a cada uno de los siguientes
a
puntos:
1. Describe qu´ objetos condici´n has usado y el prop´sito de cada uno.
e
o
o
2. Incluye el c´digo fuente completo de la soluci´n adoptada.
o
o
3. Incluye un listado de la salida del programa.

Plantilla del monitor Estanco y la hebra Fumador

§
class Estanco extends AbstractMonitor
{ ...
public void obtenerIngredientes( int miIngrediente )
{ ...
}

creado October 4, 2013- p´gina 199 / 222
a

¤
SCD (13-14). Pr´ctica 2. Programaci´n de monitores con hebras Java..
a
o

public void ponerIngredientes( int ingred1, int ingred2 )
{ ...
}
public void esperarRecogidaIngredientes ()
{ ...
}

}
class Fumador implements Runnable
{ int miIngrediente; public Thread thr ;
...
public Fumador( int miIngrediente, ... )
{ ...
}
public void run()
{ while ( true )
{ estanco.obtenerIngredientes( miIngrediente );
try { Thread.sleep (tiempo); } catch (InterruptedException e) { }
}
}
}
¦

Plantilla de la hebra Estanquero

§
class Estanquero implements Runnable
{ public Thread thr ;
...
public void run()
{ int ingrediente1, ingrediente2;
while (true)
{ do
{ ingrediente1 = (int) (Math.random () * 3.0);
ingrediente2 = (int) (Math.random () * 3.0);
} while( ingrediente1 == ingrediente2 );
estanco.ponerIngredientes( ingrediente1, ingrediente2 );
estanco.esperarRecogidaIngredientes() ;
}
}
}
¦

9.6

El problema del barbero durmiente.

El problema del barbero durmiente (1)

El problema del barbero durmiente es representativo de cierto tipo de problemas reales: ilustra perfectamente
la relaci´n de tipo cliente-servidor que a menudo aparece entre los procesos.
o

• Una barber´ tiene dos puertas y unas cuantas sillas. Los clientes entran por una puerta y salen por
ıa
otra.

creado October 4, 2013- p´gina 200 / 222
a

¥

¤

¥
SCD (13-14). Pr´ctica 2. Programaci´n de monitores con hebras Java..
a
o

• Solamente un cliente o el barbero pueden moverse por el local en cada momento.

• El barbero continuamente sirve clientes, uno cada vez. Cuando no hay ning´n cliente en la barber´
u
ıa,
el barbero est´ durmiendo en su silla.
a
• Cuando un cliente entra en la barber´ y encuentra al barbero durmiendo, lo despierta, se sienta en
ıa
su silla, y espera a que el barbero termine de pelarlo.

• Si el barbero est´ ocupado cuando un nuevo cliente entra, el cliente se sienta en una silla de la sala
a
de espera y espera a que el barbero lo despierte.

El problema del barbero durmiente(2)

• Cuando el barbero termina de pelar al cliente actual, lo despierta, abre la puerta de salida, y espera
a que el cliente salga y cierre la puerta para pasar al siguiente cliente.
• A continuaci´n, si hay clientes esperando, el barbero despierta a uno y espera a que se siente en la
o
silla para pelarlo.

• Si no hay clientes esperando, el barbero se sienta en su silla y duerme hasta que llegue alg´n cliente
u
y lo despierte.

Ejercicio propuesto

Escribir un programa Java para el problema del barbero durmiente. Los clientes y el barbero son hebras, y la
barber´ es un monitor que implementa la interacci´n entre ´stos. Los clientes llaman a cortarPelo para
ıa
o
e
obtener servicio del barbero, despert´ndolo o esperando a que termine con el cliente anterior. El barbero
a
llama a siguienteCliente para esperar la llegada de un nuevo cliente y servirlo. Cuando termina de
pelar al cliente actual llama a finCliente, indic´ndole que puede salir de la barber´ y esperando a que
a
ıa
lo haga para pasar al siguiente cliente. Usar las plantillas que se incluyen abajo.
Documentaci´n para el portafolio
o

Los alumnos redactar´n un documento con lo siguiente:
a

1. Descripci´n de los objetos condici´n usados y su prop´sito.
o
o
o
2. C´digo fuente completo de la soluci´n.
o
o
3. Listado de la salida del programa.

Plantilla del Monitor Barberia

§
class Barberia extends AbstractMonitor
{ ...
public void cortarPelo ()
{ ...
}
public void siguienteCliente ()
{ ...
}

¤

creado October 4, 2013- p´gina 201 / 222
a
SCD (13-14). Seminario 3. Introducci´n al paso de mensajes con MPI..
o
public void finCliente ()
{ ...
}

}
¦

¥

Plantilla de las hebras Cliente y Barbero

§
class Cliente implements Runnable
{ public Thread thr ;
...
public void run ()
{ while (true) {
barberia.cortarPelo ();
try { Thread.sleep (tiempo); } catch (InterruptedException e) { }
}
}
}
class Barbero implements Runnable
{ public Thread thr ;
...
public void run ()
{ while (true) {
barberia.siguienteCliente ();
try { Thread.sleep (tiempo); } catch (InterruptedException e) { }
barberia.finCliente ();
}
}
}
¦

creado October 4, 2013- p´gina 202 / 222
a

¤

¥
Chapter 10

Seminario 3. Introducci´n al paso de
o
mensajes con MPI.
Introducci´n
o

• El objetivo de esta pr´ctica es familiarizar al alumno con el uso de la interfaz de paso de mensajes
a
MPI y la implementaci´n OpenMPI de esta interfaz.
o
• Se indicar´n los pasos necesarios para compilar y ejecutar programas usando OpenMPI.
a

• Se presentar´n las principales caracter´
a
ısticas de MPI y algunas funciones b´sicas de comunicaci´n
a
o
entre procesos.

Enlaces para acceder a informaci´n complementaria
o
• Web oficial de OpenMPI.

• Instalaci´n de OpenMPI en Linux.
o
• Ayuda para las funciones de MPI.
• Tutorial de MPI.

203
SCD (13-14). Seminario 3. Introducci´n al paso de mensajes con MPI..
o

10.1

Message Passing Interface (MPI)

¿Qu´ es MPI?
e

• MPI es un est´ndar de programaci´n paralela mediante paso de mensajes que permite crear programas
a
o
portables y eficientes.

• Proporciona un conjunto de funciones que pueden ser utilizadas en programas escritos en C, C++,
Fortran y Ada.
• MPI-2 contiene m´s de 150 funciones para paso de mensajes y operaciones complementarias (con
a
numerosos par´metros y variantes).
a

• Muchos programas paralelos se pueden construir usando un conjunto reducido de dichas funciones
(hay 6 funciones b´sicas).
a

Modelo de Programaci´n en MPI
o

• El esquema de funcionamiento implica un n´mero fijo de procesos que se comunican mediante llamadas
u
a funciones de env´ y recepci´n de mensajes.
ıo
o

• Se sigue como modelo b´sico el estilo SPMD (Single Program Multiple Data), en el que todos los
a
procesos ejecutan un mismo programa.
• Tambi´n se permite seguir un modelo MPMD (Multiple Program Multiple Data), en el que cada proceso
e
puede ejecutar un programa diferente.
• La creaci´n e inicializaci´n de procesos no est´ definida en el est´ndar, depende de la implementaci´n.
o
o
a
a
o
En OpenMPI ser´ algo as´
ıa
ı:
¿ mpirun -np 4 -machinefile maquinas prog1
◾ Comienza 4 copias del ejecutable prog1.

◾ El archivo maquinas define la asignaci´n de procesos a m´quinas.
o
a

Aspectos de implementaci´n
o
• include “mpi.h

◾ Define constantes, tipos de datos y los prototipos de las funciones MPI.

• Las funciones devuelven un c´digo de error:
o
◾ MPI SUCCESS: Ejecuci´n correcta.
o

• MPI Status es una estructura que se obtiene cada vez que se completa la recepci´n de un mensaje.
o
Contiene 2 campos:
◾ status.MPI SOURCE: proceso fuente.

creado October 4, 2013- p´gina 204 / 222
a
SCD (13-14). Seminario 3. Introducci´n al paso de mensajes con MPI..
o
◾ status.MPI TAG: etiqueta del mensaje.

• Tipos de datos b´sicos para los mensajes en MPI: MPI CHAR, MPI INT, MPI LONG, MPI UNSIGNED CHAR,
a
MPI UNSIGNED, MPI UNSIGNED LONG, MPI FLOAT, MPI DOUBLE, MPI LONG DOUBLE, etc.
• Comunicador: es tanto un grupos de procesos como un contexto de comunicaci´n. Todas las funciones
o
de comunicaci´n necesitan como argumento un comunicador.
o

10.2

Compilaci´n y ejecuci´n de programas MPI
o
o

Compilaci´n y ejecuci´n de programas en OpenMPI
o
o

OpenMPI es una implementaci´n portable y de c´digo abierto del est´ndar MPI-2, llevada a cabo por una
o
o
a
serie de instituciones de ambito tanto acad´mico y cient´
´
e
ıfico como industrial
OpenMPI ofrece varios scripts necesarios para trabajar con programas aumentados con llamadas a funciones
de MPI. Los m´s importantes son:
a
• mpicxx: para compilar y enlazar programas C++ que hagan uso de MPI.
• mpirun: para ejecutar programas MPI.

mpicxx puede utilizarse con las mismas opciones que el compilador de C/C++ usual, p.e.:
• $ mpicxx -c ejemplo.c

• $ mpicxx -o ejemplo ejemplo.o

Compilaci´n y ejecuci´n de programas MPI
o
o

La forma m´s usual de ejecutar un programa MPI es :
a
• $ mpirun -np 4 ejemplo

• El argumento -np sirve para indicar cu´ntos procesos ejecutar´n el programa ejemplo. En este caso,
a
a
se lanzar´n cuatro procesos ejemplo.
a
• Como no se indica nada m´s, OpenMPI lanzar´ dichos procesos en la m´quina local.
a
a
a

10.3

Funciones MPI b´sicas
a

Funciones MPI b´sicas
a

Hay 6 funciones b´sicas en MPI:
a

• MPI Init: Inicializa el entorno de ejecuci´n de MPI.
o

• MPI Finalize: Finaliza el entorno de ejecuci´n de MPI.
o

u
• MPI Comm size: Determina el n´mero de procesos de un comunicador.

creado October 4, 2013- p´gina 205 / 222
a
SCD (13-14). Seminario 3. Introducci´n al paso de mensajes con MPI..
o

• MPI Comm rank: Determina el identificador del proceso en un comunicador.

• MPI Send: Operaci´n b´sica para env´ de un mensaje.
o a
ıo

• MPI Recv: Operaci´n b´sica para recepci´n de un mensaje.
o a
o

Inicializar y finalizar un programa MPI

§
int MPI_Init (int *argc, char ***argv)
¦

¤
¥

• Llamado antes de cualquier otra funci´n MPI.
o

• Si se llama m´s de una vez durante la ejecuci´n da un error.
a
o

• Los argumentos argc, argv son los argumentos de la l´
ınea de orden del programa.

§
int MPI_Finalize ( )
¦

¥

• Llamado al fin de la computaci´n.
o

• Realiza tareas de limpieza para finalizar el entorno de ejecuci´n
o

10.3.1

¤

Introducci´n a los comunicadores
o

Introducci´n a los comunicadores MPI
o

• Comunicador MPI = variable de tipo MPI Comm.

• Un comunicador est´ constituido por:
a

◾ Grupo de procesos: Subconjunto de procesos (pueden ser todos).
◾ Contexto de comunicaci´n: Ambito de paso de mensajes en el que se comunican dichos procesos.
o ´
Un mensaje enviado en un contexto s´lo puede ser recibido en dicho contexto.
o

• Todas las funciones de comunicaci´n de MPI necesitan como argumento un comunicador.
o

creado October 4, 2013- p´gina 206 / 222
a
SCD (13-14). Seminario 3. Introducci´n al paso de mensajes con MPI..
o
Introducci´n a los comunicadores
o

• MPI COMM WORLD hace referencia al comunicador universal, un comunicador predefinido por MPI
que incluye a todos los procesos de la aplicaci´n (es el comunicador por defecto).
o

• La identificaci´n de los procesos participantes en un comunicador es un´
o
ıvoca:
• Un proceso puede pertenecer a diferentes comunicadores.

• Cada proceso tiene un identificador: desde 0 a P − 1 (P es el n´mero de procesos del comunicador).
u

• Mensajes destinados a diferentes contextos de comunicaci´n no interfieren entre s´
o
ı.

Funciones para obtener informaci´n
o

§
int MPI_Comm_size ( MPI_Comm comm, int *size )
¦

¤
¥

• size : n´mero de procesos que pertenecen al comunicador comm.
u
• Ej.: MPI Comm size ( MPI COMM WORLD, &size).

§
int MPI_Comm_rank ( MPI_Comm comm, int *rank )
¦
• rank : Identificador del proceso llamador en comm.

§
Ejemplo:
#include "mpi.h"
#include <iostream>
using namespace std;
int main(int argc, char *argv[]){
int rank, size;
MPI_Init(&argc, &argv);
MPI_Comm_size(MPI_COMM_WORLD,&size);
MPI_Comm_rank(MPI_COMM_WORLD,&rank);
cout<<"Hola desde proc. "
<<rank<<" de "<<size<<endl;
MPI_Finalize();
return 0;
}
¦

¤
¥

¤§
mpicxx -o holamundo holamundo.c
mpirun -np 4 holamundo
Hola
Hola
Hola
Hola
¦

desde
desde
desde
desde

proc.
proc.
proc.
proc.

0
2
1
3

de
de
de
de

4
4
4
4

¤

¥

¥

creado October 4, 2013- p´gina 207 / 222
a
SCD (13-14). Seminario 3. Introducci´n al paso de mensajes con MPI..
o

10.3.2

Funciones b´sicas de env´ y recepci´n de mensajes
a
ıo
o

Env´ y recepci´n de mensajes
ıo
o

§
int MPI_Send(void *buf, int count, MPI_Datatype datatype, int dest,
int tag, MPI_Comm comm)
¦
• Env´ los datos (count elementos de tipo datatype almacenados a partir de buf) al proceso dest con la
ıa
etiqueta tag (entero >= 0) dentro del comunicador comm.
• Presenta una sem´ntica bloqueante con buffer (retorna cuando copia mensaje en buffer).
a

§
int MPI_Recv(void *buf, int count, MPI_Datatype datatype, int source,
int tag, MPI_Comm comm, MPI_Status *status )
¦

¤
¥

¤
¥

• Recibe mensaje de proceso source dentro del comunicador comm (sem´ntica bloqueante) y lo almacena en
a
posiciones contiguas desde buf.
• Solo se recibe desde source con etiqueta tag, aunque existen argumentos comod´ MPI ANY SOURCE,
ın:
MPI ANY TAG.

Env´ y recepci´n de mensajes (2)
ıo
o

• Argumentos count y datatype: especifican la longitud del mensaje.

• Objeto status : Estructura con campos MPI SOURCE y MPI TAG.
◾ Permite obtener informaci´n sobre el mensaje recibido.
o

◾ Tambi´n permite obtener el tama˜o del mensaje recibido:
e
n

§
int MPI_Get_count(MPI_Status *status, MPI_Datatype dtype, int *count)
¦

Ejemplo: Programa para dos procesos

§

¦

¤
¥
¤

MPI_Init( &argc, &argv );
MPI_Comm_rank( MPI_COMM_WORLD, &rank );
MPI_Comm_size( MPI_COMM_WORLD, &size );
if (rank == 0) {
value=100;
MPI_Send (&value, 1, MPI_INT, 1, 0, MPI_COMM_WORLD );}
else
MPI_Recv ( &value, 1, MPI_INT, 0, 0, MPI_COMM_WORLD, &status );
MPI_Finalize( );

creado October 4, 2013- p´gina 208 / 222
a

¥
SCD (13-14). Seminario 3. Introducci´n al paso de mensajes con MPI..
o
Ejemplo: Difusi´n de mensaje en anillo de procesos
o

§
int main(int argc, char *argv[]) {
int rank, size,value;
MPI_Status status;
MPI_Init(&argc, &argv);
MPI_Comm_rank(MPI_COMM_WORLD, &rank);
MPI_Comm_size( MPI_COMM_WORLD, &size );
do {
if (rank == 0) { scanf( "%d", &value );
MPI_Send( &value, 1, MPI_INT, rank+1, 0, MPI_COMM_WORLD ); }
else {
MPI_Recv( &value, 1, MPI_INT, rank-1, 0, MPI_COMM_WORLD, &status );
if (rank < size-1)
MPI_Send( &value, 1, MPI_INT, rank+1, 0, MPI_COMM_WORLD );}
cout<< "Soy el proceso "<<rank<<" y he recibido "<<value<<endl;
} while (value >= 0);
MPI_Finalize(); return 0;
}
¦

10.4

Paso de mensajes s´
ıncrono en MPI

Env´ en modo s´
ıo
ıncrono

En MPI existe una funci´n de env´ bloqueante sin buffer (env´ s´
o
ıo
ıo ıncrono):

§
int MPI_Ssend(void* buf, int count, MPI_Datatype datatype, int dest,
int tag, MPI_Comm comm)
¦

• Presenta los mismos argumentos que MPI Send.

• La operaci´n de env´ finalizar´ solo cuando el correspondiente Recv sea invocado y el receptor haya
o
ıo
a
comenzado a recibir el mensaje.

• Cuando MPI Ssend devuelve el control, la zona de memoria que alberga el dato podr´ ser reutilizada
a
y el receptor habr´ alcanzado el punto de su ejecuci´n que corresponde a la llamada de la funci´n de
a
o
o
recepci´n.
o

• Si la correspondiente operaci´n de recepci´n usada es bloqueante (MPI Recv, por ejemplo), la
o
o
sem´ntica del paso de mensajes es puramente s´
a
ıncrona (existe una cita entre emisor y receptor).

Ejemplo: Intercambio s´
ıncrono entre pares de procesos

creado October 4, 2013- p´gina 209 / 222
a

¤

¥

¤
¥
SCD (13-14). Seminario 3. Introducci´n al paso de mensajes con MPI..
o

§
int main(int argc, char *argv[]) {
int rank, size, mivalor, valor;
MPI_Status status;
MPI_Init(&argc, &argv);
MPI_Comm_rank(MPI_COMM_WORLD, &rank);
MPI_Comm_size( MPI_COMM_WORLD, &size );
mivalor=rank*(rank+1);
if (rank %2 == 0) {
// El orden de las operaciones es importante
MPI_Ssend( &mivalor, 1, MPI_INT, rank+1, 0, MPI_COMM_WORLD );
MPI_Recv( &valor, 1, MPI_INT, rank+1, 0, MPI_COMM_WORLD, &status );}
else {
MPI_Recv( &valor, 1, MPI_INT, rank-1, 0, MPI_COMM_WORLD, &status );
MPI_Ssend( &mivalor, 1, MPI_INT, rank-1, 0, MPI_COMM_WORLD );}
cout<< "Soy el proceso "<<rank<<" y he recibido "<<valor<<endl;
MPI_Finalize(); return 0;
}
¦

10.5

Comunicaci´n no bloqueante
o

Comunicaci´n no bloqueante
o

• Las operaciones de comunicaci´n vistas anteriormente son bloqueantes.
o

◾ Incluso MPI Send puede causar el bloqueo del emisor si la implementaci´n limita en exceso el
o
tama˜o del buffer y se env´ mensajes muy largos.
n
ıan

• Se necesitan operaciones de comunicaci´n no bloqueantes
o
◾ Sondeo de mensajes. Comunicaci´n As´
o
ıncrona:

▸ MPI Iprobe: Chequeo no bloqueante para un mensaje.
▸ MPI Probe: Chequeo bloqueante para un mensaje.

◾ Env´
ıo-Recepci´n no bloqueantes sin buffer:
o
▸
▸
▸
▸

MPI
MPI
MPI
MPI

Isend: Inicia env´ pero retorna antes de copiar en buffer.
ıo
Irecv: Inicia recepci´n pero retorna antes de recibir.
o
Test: Chequea si la operaci´n no bloqueante ha finalizado.
o
Wait: Bloquea hasta que acabe la operaci´n no bloqueante.
o

Comunicaci´n as´
o
ıncrona

El acceso no estructurado a un recurso compartido requiere comprobar la existencia de mensajes sin recibirlos.
creado October 4, 2013- p´gina 210 / 222
a

¤

¥
SCD (13-14). Seminario 3. Introducci´n al paso de mensajes con MPI..
o

§
int MPI_Iprobe(int source, int tag, MPI_Comm comm,
int *flag, MPI_Status *status)
¦
• No bloquea si no hay mensajes. Si hay mensaje, se recibe con MPI Recv.

¤

§
int MPI_Probe(int source, int tag, MPI_Comm comm, MPI_Status *status)
¦
• Retorna s´lo cuando hay alg´n mensaje que encaje con los argumentos.
o
u

¤

• Si (flag ¿ 0), eso indica que hay un mensaje pendiente que encaja con (source, tag, comm).
• El argumento status permite obtener m´s informaci´n sobre el mensaje pendiente de recepci´n.
a
o
o

• Permite esperar la llegada de un mensaje sin conocer su procedencia, etiqueta o tama˜o.
n

Ejemplo: Sondeo continuo de varias fuentes desconocidas

§
int rank, size, flag, buf, src,tag;
...
MPI_Comm_rank(MPI_COMM_WORLD, &rank);
MPI_Comm_size( MPI_COMM_WORLD, &size );
if (rank == 0) {
int contador=0;
while (contador<10*(size-1)){
MPI_Iprobe(MPI_ANY_SOURCE,MPI_ANY_TAG,MPI_COMM_WORLD, &flag, &status);
if (flag>0){
MPI_Recv(&buf, 1, MPI_INT, MPI_ANY_SOURCE, MPI_ANY_TAG,
MPI_COMM_WORLD, &status );
src=status.MPI_SOURCE; tag=status.MPI_TAG;
cout<<"Mensaje de "<<src<<" con tag= "<<tag<<endl;
contador++;}
}
cout<< "Total de mensajes recibidos: "<< contador<<endl;
}
else
for (int i=0; i<10; i++)
MPI_Send( &buf, 1, MPI_INT, 0, i, MPI_COMM_WORLD );
...
¦

Ejemplo: Recepci´n de mensaje con tama˜o y fuente desconocidos
o
n

§
int count, *buf, source;
// Me bloqueo hasta que se detecte un mensaje
MPI_Probe (MPI_ANY_SOURCE, 0,comm, &status);
// Se averigua el tama˜o y el proceso emisor del mensaje
n
MPI_Get_count(status, MPI_INT, &count);
source= status.MPI_SOURCE;
// Se reserva memoria para recibir el mensaje
buf=malloc(count*sizeof(int));
// Se recibe el mensaje
MPI_Recv(buf, count, MPI_INT, source, 0, comm, &status);
¦

creado October 4, 2013- p´gina 211 / 222
a

¥

¥

¤

¥
¤

¥
SCD (13-14). Seminario 3. Introducci´n al paso de mensajes con MPI..
o
Operaciones no bloqueantes

§
int MPI_Isend(void* buf, int count, MPI_Datatype datatype, int dest,
int tag, MPI_Comm comm, MPI_Request *request)
int MPI_Irecv(void* buf, int count, MPI_Datatype datatype, int source,
int tag, MPI_Comm comm, MPI_Request *request)
¦

¤

¥

Los argumentos son similares a MPI Send excepto:

• Argumento request: Identifica operaci´n cuyo estado se pretende consultar o se espera que finalice.
o

§
¦

• No incluye argumento status: Se puede obtener con otras 2 funciones de chequeo de estado.

int MPI_Request_free(MPI_Request *request)

¥

• Liberaci´n expl´
o
ıcita de un objeto request

Operaciones no bloqueantes. Chequeo de estado

§
int MPI_Test(MPI_Request *request, int *flag, MPI_Status *status)
¦

§
¦

¤

• Si flag > 0 entonces la operaci´n identificada ha finalizado, libera request e inicializa status.
o

int MPI_Wait(MPI_Request *request, MPI_Status *status)

¤
¥

¤
¥

• Produce bloqueo hasta que la operaci´n chequeada finaliza (es segura).
o

Es posible conectar operaciones no bloqueantes con sus contrapartes bloqueantes.
Ejemplo: Intercambio de mensajes usando operaciones no bloqueantes

§
int main(int argc, char *argv[]) {
int rank, size, vecino, mivalor, valor;
MPI_Status status;
MPI_Request request_send,request_recv;
MPI_Init(&argc, &argv);
MPI_Comm_rank(MPI_COMM_WORLD, &rank);
MPI_Comm_size( MPI_COMM_WORLD, &size );
mivalor=rank*(rank+1);
if (rank %2 == 0) vecino=rank+1;
else vecino=rank-1;

// Las siguientes operaciones pueden aparecer en cualquier orden
MPI_Irecv(&valor,1,MPI_INT,vecino,0,MPI_COMM_WORLD,&request_recv);
MPI_Isend(&mivalor,1,MPI_INT,vecino,0,MPI_COMM_WORLD,&request_send);
... // Aqu´ se puede hacer algo que no use mivalor ni altere valor
ı

creado October 4, 2013- p´gina 212 / 222
a

¤
SCD (13-14). Pr´ctica 3. Implementaci´n de algoritmos distribuidos con MPI..
a
o
MPI_Wait(&request_send,&status); //Me bloqueo hasta que sea seguro
MPI_Wait(&request_recv,&status);

cout<< "Soy el proceso "<<rank<<" y he recibido "<<valor<<endl;
MPI_Finalize(); return 0;
}
¦

creado October 4, 2013- p´gina 213 / 222
a

¥
SCD (13-14). Pr´ctica 3. Implementaci´n de algoritmos distribuidos con MPI..
a
o

creado October 4, 2013- p´gina 214 / 222
a
Chapter 11

Pr´ctica 3. Implementaci´n de algoritmos
a
o
distribuidos con MPI.
11.1

Objetivos

Objetivos

• El objetivo general es iniciarse en la programaci´n de algoritmos distribuidos.
o

• Conocer varios problemas sencillos de sincronizaci´n y su soluci´n distribuida mediante el uso de la
o
o
interfaz de paso de mensajes MPI:
◾ Dise˜ar una soluci´n distribuida al problema del productor-consumidor con buffer acotado para
n
o
varios productores y varios consumidores, usando MPI.

11.2

11.2.1

◾ Dise˜ar diversas soluciones al problema de la cena de los fil´sofos usando MPI.
n
o

Productor-Consumidor con buffer acotado en MPI
Aproximaci´n inicial en MPI
o

Aproximaci´n inicial en MPI
o

• Supongamos que disponemos de una versi´n distribuida del problema del productor-consumidor que usa tres
o
procesos y la interfaz de paso de mensajes MPI. Para ello, tendremos un proceso productor (proceso 0 del
comunicador universal) que producir´ datos, un proceso Buffer (proceso 1) que gestionar´ el intercambio de
a
a
datos y un proceso consumidor que procesar´ los datos (proceso 2). El esquema de comunicaci´n entre estos
a
o
procesos se muestra a continuaci´n:
o

215
SCD (13-14). Pr´ctica 3. Implementaci´n de algoritmos distribuidos con MPI..
a
o

• El proceso Productor se encarga de ir generando enteros comenzando por el 0 y envi´rselos al proceso
a
Buffer. El proceso Consumidor env´ peticiones al proceso Buffer, recibe los enteros de Buffer, los
ıa
imprime por pantalla y calcula su ra´ cuadrada.
ız

• El proceso Buffer deber´ atender las peticiones de ambos procesos (Productor y Consumidor).
ıa

Aproximaci´n inicial. C´digo usando MPI
o
o

• Una aproximaci´n inicial al problema se muestra en el siguiente c´digo MPI para tres procesos, que
o
o
modela la interacci´n de los mismos de una forma incorrecta al forzar una excesiva sincronizaci´n entre
o
o
productor y consumidor.

§
#include "mpi.h"
...
#define Productor 0
#define Buffer 1
#define Consumidor 2
#define ITERS 20
...
int main(int argc, char *argv[]) {
int rank,size;
MPI_Init( &argc, &argv );
MPI_Comm_rank( MPI_COMM_WORLD, &rank );
MPI_Comm_size( MPI_COMM_WORLD, &size );
if (rank == Productor) productor();
else if (rank==Buffer) buffer();
else consumidor();
MPI_Finalize( );
return 0;
}
¦

¤

¥

Proceso Productor, Consumidor y Buffer

§
void productor(){
for (unsigned int i=0;i<ITERS;i++){
cout<< "Productor produce valor "<<i<<endl<<flush;
MPI_Ssend( &i, 1, MPI_INT, Buffer, 0, MPI_COMM_WORLD );}
}
¦
§
void consumidor(){
int value,peticion=1; float raiz;
MPI_Status status;
for (unsigned int i=0;i<ITERS;i++){
MPI_Ssend(&peticion,1, MPI_INT, Buffer, 0, MPI_COMM_WORLD);
MPI_Recv(&value,
1, MPI_INT, Buffer, 0, MPI_COMM_WORLD,&status );
cout<< "Consumidor recibe valor "<<value<<" de Buffer "<<endl<<flush;
raiz=sqrt(value);}
}
¦

creado October 4, 2013- p´gina 216 / 222
a

¤

¥
¤

¥
SCD (13-14). Pr´ctica 3. Implementaci´n de algoritmos distribuidos con MPI..
a
o

§
void buffer(){
int value,peticion; MPI_Status status;
for (unsigned int i=0;i<ITERS;i++){
MPI_Recv(&value,
1, MPI_INT, Productor, 0, MPI_COMM_WORLD,&status );
MPI_Recv(&peticion, 1, MPI_INT, Consumidor, 0, MPI_COMM_WORLD,&status );
MPI_Ssend( &value, 1, MPI_INT, Consumidor, 0, MPI_COMM_WORLD);
cout<< "Buffer envia valor "<< value << " a Consumidor "<<endl<<flush;}
}
¦

11.2.2

¤

¥

Soluci´n con selecci´n no determinista
o
o

Soluci´n con selecci´n no determinista
o
o

• Se debe permitir que el productor pueda enviar TAM datos sin tener que interrumpirse, y que el
consumidor no se retrase cuando haya datos almacenados en el proceso buffer.

• Una forma de corregir dicho c´digo consiste en usar una sentencia de selecci´n no determinista de
o
o
´rdenes con guarda en el proceso Buffer que permita cierta asincron´ entre productor y consumidor
o
ıa
en funci´n del tama˜o del buffer temporal (TAM).
o
n
• En MPI, no hay ninguna sentencia de selecci´n no determinista de ´rdenes con guarda, pero es f´cil
o
o
a
emularla con las funciones de sondeo MPI Probe y/o MPI Iprobe.

Proceso Buffer con selecci´n no determinista
o

§
void buffer(){
int value[TAM], peticion, pos=0,rama; MPI_Status status;
for (unsigned int i=0;i<ITERS*2;i++){
if (pos==0) rama=0;
//El consumidor no puede consumir
else if (pos==TAM) rama=1; // El productor no puede producir
else{ //Ambas guardas son ciertas
MPI_Probe(MPI_ANY_SOURCE,MPI_ANY_TAG, MPI_COMM_WORLD,&status);
if (status.MPI_SOURCE==Productor) rama =0; else rama=1;
}
switch(rama){
case 0:
MPI_Recv(&value[pos],1,MPI_INT, Productor,0,MPI_COMM_WORLD,&status);
cout<< "Buffer recibe "<< value[pos] << " de Prod. "<<endl<<flush;
pos++;
break;
case 1:
MPI_Recv(&peticion,1,MPI_INT,Consumidor,0,MPI_COMM_WORLD,&status);
MPI_Ssend(&value[pos-1],1,MPI_INT,Cons., 0, MPI_COMM_WORLD);
cout<< "Buffer envia "<< value[pos-1] << " a Cons."<<endl<<flush;
pos--;
break;}
}
}
¦

creado October 4, 2013- p´gina 217 / 222
a

¤

¥
SCD (13-14). Pr´ctica 3. Implementaci´n de algoritmos distribuidos con MPI..
a
o
Ejercicio propuesto

Extender el programa MPI anteriormente presentado que implementa el productor-consumidor con buffer
acotado (los fuentes del programa se proporcionan junto con el gui´n de pr´cticas) para que el proceso
o
a
buffer d´ servicio a 5 productores y 4 consumidores. Para ello, se lanzar´n 10 procesos y asumiremos
e
a
que los procesos 0 . . . 4 son productores, el proceso Buffer es el proceso 5 y el resto de procesos en el
comunicador universal (6 . . . 9) son consumidores.
Documentaci´n para el portafolios
o

Los alumnos redactar´n un documento donde se responda de forma razonada a cada uno de los siguientes
a
puntos:
1. Describe qu´ cambios has realizado sobre el programa de partida y el prop´sito de dichos cambios.
e
o
2. Incluye el c´digo fuente completo de la soluci´n adoptada.
o
o
3. Incluye un listado parcial de la salida del programa.

11.3

11.3.1

Cena de los Fil´sofos
o

Cena de los fil´sofos en MPI
o

Cena de los fil´sofos en MPI.
o

• Se pretende realizar una implementaci´n del problema de la cena de los fil´sofos en MPI utilizando
o
o
el siguiente esquema:

• Tenemos 5 procesos fil´sofos y 5 procesos tenedor (10 procesos en total). Supondremos que los procs.
o
fil´sofos se identifican con n´mero pares y los tenedores con n´meros impares. El fil´sofo i (i = 0, ..., 4)
o
u
u
o
ser´ el proc. 2i y el tenedor i ser´ el 2i + 1.
a
a

Cena de los fil´sofos. Programa principal
o
creado October 4, 2013- p´gina 218 / 222
a
SCD (13-14). Pr´ctica 3. Implementaci´n de algoritmos distribuidos con MPI..
a
o

§
#include "mpi.h"
#include <iostream>
#include <time.h>
#include <stdlib.h>
...
void Filosofo(int id, int nprocesos); // Codigo proc. Filosofo
void Tenedor (int id, int nprocesos); // Codigo proc. Tenedor

int main(int argc,char** argv ){
int rank,size;
srand(time(0));
MPI_Init( &argc, &argv );
MPI_Comm_rank( MPI_COMM_WORLD, &rank );
MPI_Comm_size( MPI_COMM_WORLD, &size );
if( size!=10){
if (rank == 0) cout<<"El numero de procesos debe ser 10"<<endl<<flush;
MPI_Finalize( ); return 0;
}
if ((rank%2) == 0) Filosofo(rank,size); // Los pares son Filosofos
else Tenedor(rank,size);
// Los impares son Tenedores
MPI_Finalize();
return 0;
}
¦

¤

¥

Procesos fil´sofos
o

• En principio, cada fil´sofo realiza repetidamente la siguiente secuencia de acciones:
o
◾ Pensar (sleep aleatorio).

◾ Tomar los tenedores (primero el tenedor izquierdo y despu´s el derecho).
e
◾ Comer (sleep aleatorio).

◾ Soltar tenedores (en el mismo orden).

• Las acciones pensar y comer pueden implementarse mediante un mensaje por pantalla seguido de
un retardo durante un tiempo aleatorio. Las acciones de tomar tenedores y soltar tenedores pueden
implementarse enviando mensajes de petici´n y de liberaci´n a los procesos tenedor situados a ambos
o
o
lados de cada fil´sofo.
o

Plantilla de la Funci´n Filosofo
o

§
void Filosofo(int id, int nprocesos){
int izq=(id+1)%nprocesos;int der=(id-1+nprocesos)%nprocesos;
while(1){
//Solicita tenedor izquierdo
cout<<"Filosofo "<<id<< " solicita tenedor izq ..."<<izq <<endl<<flush;
// ...
//Solicita tenedor derecho

creado October 4, 2013- p´gina 219 / 222
a

¤
SCD (13-14). Pr´ctica 3. Implementaci´n de algoritmos distribuidos con MPI..
a
o

cout<<"Filosofo "<<id<< " coge tenedor der ..."<<der <<endl<<flush;
// ...
cout<<"Filosofo "<<id<< " COMIENDO"<<endl<<flush;
sleep((rand() % 3)+1); //comiendo
//suelta el tenedor izquierdo
cout<<"Filosofo "<<id<< " suelta tenedor izq ..."<<izq <<endl<<flush;
// ...
//suelta el tenedor derecho
cout<<"Filosofo "<<id<< " suelta tenedor der ..."<<der <<endl<<flush;
// ...
cout<<"Filosofo "<<id<< " PENSANDO"<<endl<<flush;
sleep((rand()%3)+1 );//pensando

}
}
¦

¥

Procesos tenedor

• Un tenedor solamente podr´ ser asignado a uno de los dos fil´sofos que realicen la petici´n. Hasta
a
o
o
que el tenedor no sea liberado no podr´ ser asignado de nuevo. Cada proceso tenedor tendr´ que
a
a
ejecutar repetidamente la siguiente secuencia de acciones:
◾ Esperar mensajes de petici´n de tenedor y recibir uno.
o
◾ Esperar mensaje de liberaci´n.
o

§
void Tenedor(int id, int nprocesos){
int buf; MPI_Status status; int Filo;
while(1){
// Espera un peticion desde cualquier filosofo vecino ...
// ...
// Recibe la peticion del filosofo ...
// ...
cout<<"Ten. "<<id<<" recibe petic. de "<<Filo<<endl<<flush;
// Espera a que el filosofo suelte el tenedor...
// ...
cout<<"Ten. "<<id<<" recibe liberac. de "<<Filo<<endl<<flush;
}
}
¦

Ejercicio propuesto

• Implementar una soluci´n distribuida al problema de los fil´sofos de acuerdo con el esquema descrito
o
o
en las plantillas. Usar la operaci´n s´
o ıncrona de env´ MPI Ssend para realizar las peticiones y
ıo
liberaciones de tenedores.
• El esquema propuesto (cada fil´sofo coge primero el tenedor de su izquierda y despu´s el de la derecha)
o
e
puede conducir a interbloqueo. Identificar la secuencia de peticiones de fil´sofos que conduce a ino
terbloqueo en el programa y realizar peque˜as modificaciones en el programa (y en el comportamiento
n
de las entidades que participan) que eliminan la posibilidad de interbloqueo (sin a˜adir nuevos pron
cesos).

creado October 4, 2013- p´gina 220 / 222
a

¤

¥
SCD (13-14). Pr´ctica 3. Implementaci´n de algoritmos distribuidos con MPI..
a
o
Documentaci´n para el portafolios
o

Los alumnos redactar´n un documento donde se responda de forma razonada a cada uno de los siguientes
a
puntos:
1. Describe los aspectos m´s destacados de tu soluci´n al problema de los fil´sofos, la situaci´n que
a
o
o
o
conduce al interbloqueo y tu soluci´n al problema del interbloqueo.
o
2. Incluye el c´digo fuente completo de la soluci´n adoptada para evitar la posibilidad de interbloqueo.
o
o
3. Incluye un listado parcial de la salida de este programa.

11.3.2

Cena de los fil´sofos con camarero en MPI
o

Cena de los fil´sofos con camarero
o

• Una forma de evitar la posibilidad de interbloqueo consiste en impedir que todos los fil´sofos intenten
o
ejecutar la acci´n de “tomar tenedor al mismo tiempo. Para ello podemos usar un proceso camarero
o
central que permita sentarse a la mesa como m´ximo a 4 fil´sofos. Podemos suponer que tenemos 11
a
o
procesos y que el camarero es el proc. 10.

Proceso fil´sofo con Camarero central
o

• Ahora, cada fil´sofo ejecutar´ repetidamente la siguiente secuencia de acciones:
o
a
◾
◾
◾
◾
◾
◾

Pensar
Sentarse
Tomar tenedores
Comer
Soltar tenedores
Levantarse

• Cada fil´sofo pedir´ permiso para sentarse o levantarse enviando un mensaje al camarero, el cual
o
a
llevar´ una cuenta del n´mero de fil´sofos que hay sentados a la mesa en cada momento.
a
u
o

creado October 4, 2013- p´gina 221 / 222
a
SCD (13-14). Pr´ctica 3. Implementaci´n de algoritmos distribuidos con MPI..
a
o
Ejercicio propuesto

• Implementar una soluci´n distribuida al problema de los fil´sofos con camarero central que se ha
o
o
descrito, usando MPI.
• Documentaci´n para el portafolios
o

Los alumnos redactar´n un documento donde se responda de forma razonada a cada uno de los sigua
ientes puntos:
1. Describe tu soluci´n al problema de los fil´sofos con camarero central.
o
o
2. Incluye el c´digo fuente completo de la soluci´n adoptada.
o
o
3. Incluye un listado parcial de la salida del programa.

creado October 4, 2013- p´gina 222 / 222
a

Más contenido relacionado

PDF
Matlab adv esp
PDF
Introduccion poo con_java
PDF
Algoritmos programacion-python
PDF
Algoritmos programacion-python
PDF
Topo gralmana
PDF
Introducción a la programación en c
PDF
Manual
PDF
Hibernate reference
Matlab adv esp
Introduccion poo con_java
Algoritmos programacion-python
Algoritmos programacion-python
Topo gralmana
Introducción a la programación en c
Manual
Hibernate reference

La actualidad más candente (15)

PDF
manual de visual basic.net 2008
PDF
Apunts dintel ligencia_artificial
PDF
Manual de usuario l850
PDF
PDF
Balanza 920i
PDF
Manual sony
PDF
Desarrollo proyectos-informaticos-con-java
PDF
Plan de mantenimiento de una desalinizadora
PDF
Instrucciones y registros del procesador core i5-450m
PDF
Unity v41 manual de referencia
PDF
manual de impresora
PDF
Alejandro tfm
PDF
Ecosys m2030dn ...535dn_og_es
PDF
Calculo integral rojas
PDF
Electronicadigital
manual de visual basic.net 2008
Apunts dintel ligencia_artificial
Manual de usuario l850
Balanza 920i
Manual sony
Desarrollo proyectos-informaticos-con-java
Plan de mantenimiento de una desalinizadora
Instrucciones y registros del procesador core i5-450m
Unity v41 manual de referencia
manual de impresora
Alejandro tfm
Ecosys m2030dn ...535dn_og_es
Calculo integral rojas
Electronicadigital
Publicidad

Similar a Scd 13-14 todo (20)

PDF
ApuntesC++.pdf
PDF
Algoritmos y programacion_i_-_con_lengua
PDF
Fundamentos de Programacion.pdf
PDF
Sistemas_operativos_Daniel_Sol_Llaven.pdf
PDF
Fundamentos de Programación con Lenguaje de Programación C++
PDF
El lenguaje de programación c++
PDF
Introducción a la programación en C
PDF
PDF
Programacion en Phyton desde ce..........................ro
PDF
Conceptos informáticos generales
PDF
Tutorial JSF
PDF
teoria_Simulacion.pdf
PDF
Desarrollo proyectos-informaticos-con-java
PDF
Libro javacontapa
PDF
Libro javacontapa
PDF
Manual referencia cxx
PDF
Introduccion a la_programacion_con_c
PDF
Libro programación-en-c++
ApuntesC++.pdf
Algoritmos y programacion_i_-_con_lengua
Fundamentos de Programacion.pdf
Sistemas_operativos_Daniel_Sol_Llaven.pdf
Fundamentos de Programación con Lenguaje de Programación C++
El lenguaje de programación c++
Introducción a la programación en C
Programacion en Phyton desde ce..........................ro
Conceptos informáticos generales
Tutorial JSF
teoria_Simulacion.pdf
Desarrollo proyectos-informaticos-con-java
Libro javacontapa
Libro javacontapa
Manual referencia cxx
Introduccion a la_programacion_con_c
Libro programación-en-c++
Publicidad

Más de Marlene Vásquez (6)

PDF
Plan iteración 2
PDF
Plan iteración 1
PDF
PDF
Plan entregas meetmev1.0
PDF
Informe iteración 2
PDF
Informe Iteración 1
Plan iteración 2
Plan iteración 1
Plan entregas meetmev1.0
Informe iteración 2
Informe Iteración 1

Scd 13-14 todo

  • 1. Sistemas Concurrentes y Distribuidos. Gu´ apuntes, problemas, seminarios y pr´cticas. ıa, a Curso 2013-14 1
  • 2. 2
  • 3. Contents I Gu´ de la asignatura ıa 9 1 Gu´ de la asignatura ıa 1.1 Datos generales . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 11 1.4 Bibliograf´ . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 16 ıa 1.2 1.3 II 11 Objetivos y temario . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 12 Metodolog´ docente y evaluaci´n . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 13 ıa o Apuntes de teor´ ıa 19 2 Tema 1. Introducci´n. o 2.1 2.2 2.3 2.4 2.5 2.6 21 Conceptos b´sicos y motivaci´n . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 21 a o 2.1.1 Conceptos b´sicos relacionados con la concurrencia . . . . . . . . . . . . . . . . . . . . . . 21 a 2.2.1 Consideraciones sobre el hardware . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 22 2.1.2 Motivaci´n de la Programaci´n concurrente . . . . . . . . . . . . . . . . . . . . . . . . . . . . 22 o o Modelo abstracto y consideraciones sobre el hardware . . . . . . . . . . . . . . . . . . . . . . . . . 22 2.2.2 Modelo Abstracto de concurrencia . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 25 Exclusi´n mutua y sincronizaci´n . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 30 o o 2.3.1 2.3.2 Concepto de exclusi´n mutua . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 31 o Condici´n de sincronizaci´n . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 32 o o Propiedades de los sistemas concurrentes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 33 2.4.1 2.4.2 Correcci´n de un sistema concurrente . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 33 o Propiedades de seguridad y vivacidad . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 34 Verificaci´n de programas concurrentes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 35 o 2.5.1 2.5.2 Verificaci´n de programas concurrentes. Introducci´n . . . . . . . . . . . . . . . . . . . . . . 35 o o Enfoque axiom´tico para la verificaci´n . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 35 a o Problemas del tema 1. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 36 3 Tema 2. Sincronizaci´n en memoria compartida. o 3.1 43 Introducci´n a la sincronizaci´n en memoria compartida. . . . . . . . . . . . . . . . . . . . . . . . . . 43 o o 3
  • 4. CONTENTS 3.2 3.3 3.1.1 Estructura de los procesos con Secciones Cr´ ıticas . . . . . . . . . . . . . . . . . . . . . . . . 44 3.2.1 Refinamiento sucesivo de Dijkstra . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 47 3.1.2 3.5 3.2.2 3.2.3 3.2.4 Algoritmo de Dekker . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 51 Algoritmo de Peterson . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 52 Algoritmo de Peterson para n procesos. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 54 Soluciones hardware con espera ocupada (cerrojos) para E.M. . . . . . . . . . . . . . . . . . . . . . 56 3.3.1 Introducci´n . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 56 o 3.3.4 Desventajas de los cerrojos. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 59 3.3.2 3.3.5 La instrucci´n LeerAsignar. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 57 o La instrucci´n Intercambia. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 58 o Uso de los cerrojos. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 60 Sem´foros para sincronizaci´n . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 60 a o 3.4.1 3.4.2 3.4.3 3.4.4 Introducci´n . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 60 o Estructura de un sem´foro . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 61 a Operaciones sobre los sem´foros. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 61 a Uso de los sem´foros . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 62 a Monitores como mecanismo de alto nivel . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 63 3.5.1 3.5.2 3.5.3 3.5.4 3.5.5 3.6 Propiedades para exclusi´n mutua . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 45 o Soluciones software con espera ocupada para E.M. . . . . . . . . . . . . . . . . . . . . . . . . . . . . 46 3.3.3 3.4 CONTENTS 3.5.6 3.5.7 Fundamento te´rico de los monitores . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 63 o Definici´n de monitor . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 64 o Funcionamiento de los monitores . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 67 Sincronizaci´n en monitores . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 69 o Sem´ntica de las se˜ales de los monitores . . . . . . . . . . . . . . . . . . . . . . . . . . . . 74 a n Implementaci´n de monitores . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 78 o Verificaci´n de monitores . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 79 o Problemas del tema 2. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 80 4 Tema 3. Sistemas basados en paso de mensajes. 4.1 4.2 93 Mecanismos b´sicos en sistemas basados en paso de mensajes . . . . . . . . . . . . . . . . . . . . 93 a 4.1.1 Introducci´n . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 93 o 4.1.4 Espera selectiva . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 106 4.1.2 4.1.3 Vista logica arquitectura y modelo de ejecuci´n . . . . . . . . . . . . . . . . . . . . . . . . . 94 o Primitivas b´sicas de paso de mensajes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 95 a Paradigmas de interacci´n de procesos en programas distribuidos . . . . . . . . . . . . . . . . . . 111 o 4.2.1 4.2.2 4.2.3 Introducci´n . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 111 o Maestro-Esclavo . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 111 Iteraci´n s´ o ıncrona . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 113 4
  • 5. CONTENTS 4.3 4.4 CONTENTS 4.2.4 Encauzamiento (pipelining) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 115 4.3.2 El paradigma Cliente-Servidor . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 117 Mecanismos de alto nivel en sistemas distribuidos . . . . . . . . . . . . . . . . . . . . . . . . . . . . 116 4.3.1 4.3.3 4.3.4 Introducci´n . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 116 o Llamada a Procedimiento (RPC) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 118 Java Remote Method Invocation (RMI) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 120 Problemas del tema 3. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 128 5 Tema 4. Introducci´n a los sistemas de tiempo real. o 5.1 5.2 III Concepto de sistema de tiempo real. Medidas de tiempo y modelo de tareas. . . . . . . . . . . . 133 5.1.1 5.1.2 5.1.3 Definici´n, tipos y ejemplos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 133 o Propiedades de los Sistemas de Tiempo Real . . . . . . . . . . . . . . . . . . . . . . . . . . 136 Modelo de Tareas . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 138 Esquemas de planificaci´n . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 142 o 5.2.1 5.2.2 Planificaci´n C´ o ıclica. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 143 Planificaci´n con prioridades . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 145 o Seminarios y guiones de pr´cticas a 6 Seminario 1. Programaci´n multihebra y sincronizaci´n con sem´foros. o o a 6.1 6.2 6.4 7.2 151 Hebras POSIX . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 154 6.2.1 Introducci´n . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 154 o 6.2.4 Par´metros e identificaci´n de hebras . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 158 a o 6.2.2 6.2.5 Creaci´n y finalizaci´n de hebras . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 155 o o Sincronizaci´n mediante uni´n . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 157 o o Ejemplo de hebras: c´lculo num´rico de integrales . . . . . . . . . . . . . . . . . . . . . . . 159 a e Introducci´n a los Sem´foros . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 163 o a Sincronizaci´n de hebras con sem´foros POSIX . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 165 o a 6.4.1 6.4.2 6.4.3 Funciones b´sicas. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 165 a Exclusi´n mutua . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 167 o Sincronizaci´n . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 168 o 7 Pr´ctica 1. Sincronizaci´n de hebras con sem´foros. a o a 7.1 149 Concepto e Implementaciones de Hebras . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 151 6.2.3 6.3 133 171 Objetivos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 171 El problema del productor-consumidor . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 171 7.2.1 7.2.2 Descripci´n del problema. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 171 o Plantillas de c´digo . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 172 o 5
  • 6. CONTENTS 7.3 CONTENTS 7.2.3 Actividades y documentaci´n . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 174 o 7.3.2 Plantillas de c´digo . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 176 o El problema de los fumadores. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 175 7.3.1 7.3.3 Descripci´n del problema. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 175 o Actividades y documentaci´n. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 176 o 8 Seminario 2. Hebras en Java. 8.1 8.2 8.3 8.4 8.5 8.6 179 Hebras en Java . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 180 Creaci´n de hebras en Java . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 180 o Estados de una hebra Java . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 182 Prioridades y planificaci´n. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 184 o 8.4.1 Un ejemplo m´s completo . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 184 a 8.5.2 Ejemplo: C´lculo de m´ltiplos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 187 a u Interacci´n entre hebras Java. Objetos compartidos . . . . . . . . . . . . . . . . . . . . . . . . . . . . 186 o 8.5.1 Implementando exclusi´n mutua en Java. C´digo y m´todos sincronizados. . . . . . . . . 186 o o e Compilando y ejecutando programas Java . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 189 9 Pr´ctica 2. Programaci´n de monitores con hebras Java. a o 9.1 9.2 9.3 9.4 9.5 9.6 191 Objetivos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 191 Implementaci´n de monitores nativos de Java . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 191 o 9.2.1 9.2.2 Monitores como Clases en Java . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 191 M´todos de espera y notificaci´n. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 192 e o Implementaci´n en Java de monitores estilo Hoare . . . . . . . . . . . . . . . . . . . . . . . . . . . . 195 o Productor-Consumidor con buffer limitado . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 198 El problema de los fumadores . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 199 El problema del barbero durmiente. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 200 10 Seminario 3. Introducci´n al paso de mensajes con MPI. o 203 10.1 Message Passing Interface (MPI) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 204 10.2 Compilaci´n y ejecuci´n de programas MPI . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 205 o o 10.3 Funciones MPI b´sicas . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 205 a 10.3.1 Introducci´n a los comunicadores . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 206 o 10.3.2 Funciones b´sicas de env´ y recepci´n de mensajes . . . . . . . . . . . . . . . . . . . . . . 208 a ıo o 10.4 Paso de mensajes s´ ıncrono en MPI . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 209 10.5 Comunicaci´n no bloqueante . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 210 o 11 Pr´ctica 3. Implementaci´n de algoritmos distribuidos con MPI. a o 215 11.1 Objetivos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 215 11.2 Productor-Consumidor con buffer acotado en MPI . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 215 6
  • 7. CONTENTS CONTENTS 11.2.1 Aproximaci´n inicial en MPI . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 215 o 11.2.2 Soluci´n con selecci´n no determinista . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 217 o o 11.3 Cena de los Fil´sofos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 218 o 11.3.1 Cena de los fil´sofos en MPI . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 218 o 11.3.2 Cena de los fil´sofos con camarero en MPI . . . . . . . . . . . . . . . . . . . . . . . . . . . . 221 o 7
  • 9. Part I Gu´ de la asignatura ıa 9
  • 11. Chapter 1 Gu´ de la asignatura ıa 1.1 Datos generales Datos generales de la asignatura. nombre titulaci´n o tipo curso y cuatrimestre adscrita al departamento cr´ditos totales e horas semanales presen. horas sem. no presen. m´s informaci´n a o Recursos en la Web Sistemas Concurrentes y Distribuidos Grado en Inform´tica a obligatoria (materia com´n de la rama) u 2o curso, 1er cuatrim. Lenguajes y Sistemas Inform´ticos a 6 ECTS 4 horas (2 teor´ + 2 pr´cticas) ıa a 4 horas http://lsi.ugr.es/scd https://tutor2.ugr.es http://lsi.ugr.es/lsi/node/943 En la web se pueden encontrar los siguientes recursos relacionados con la asignatura: • P´gina Web de la asignatura con documentaci´n para alumnos: a o ◾ http://lsi.ugr.es/scd (para bajar la doc. se requiere login/passwd, usar login: alumno, password: pc99scd) • Sistema web para gesti´n de grupos, notas y comunicaci´n con alumnos (sistema Tutor) o o ◾ p´g. principal: https://tutor2.ugr.es a ◾ ficha asignatura: https://tutor2.ugr.es/functions/index.php/idop 950/subject 100 • Sitio web del departamento: ◾ p´g. principal: http://lsi.ugr.es a ◾ ficha de la asignatura: http://lsi.ugr.es/lsi/node/943 ◾ profesorado depto.: http://lsi.ugr.es/lsi/personal 11
  • 12. SCD (13-14). Gu´ de la asignatura. ıa Grupos grandes (teor´ ıa) Gr A B C D Grupos peque˜os (pr´cticas). n a 1.2 Gr A1 A2 A3 B1 B2 B3 C1 C2 C3 D1 D2 D´ ıa Viernes Lunes Jueves Mi´rcoles e D´ ıa Lunes Martes Jueves Martes Mi´rcoles e Viernes Lunes Lunes Mi´rcoles e Martes Mi´rcoles e Objetivos y temario Horas 09:30-11:30 11:30-13:30 15:30-17:30 17:30-19:30 Hora 11:30-13:30 11:30-13:30 11:30-13:30 09:30-11:30 09:30-11:30 09:30-11:30 18:30-20:30 18:30-20:30 17:30-19:30 15:30-17:30 15:30-17:30 Profesor Carlos Ure˜a Almagro n Jose M. Mantas Ruiz Juan A. Holgado Terriza Pedro Villar Castro Profesor Carlos Ure˜a n Carlos Ure˜a n Ana M. S´nchez a Pedro Villar Jos´ Miguel Mantas e Ana M. S´nchez a Pedro Villar Sandra S. Rodr´ ıguez Sandra S. Rodr´ ıguez Pedro Villar M. del Mar Abad Objetivos. • Comprender la importancia de la programaci´n concurrente en las aplicaciones de hoy en d´ o ıa. • Identificar las principales caracter´ ısticas de los distintos tipos de sistemas concurrentes que existen. • Conocer y entender los problemas que plantea el desarrollo de programas concurrentes, y que no aparecen en la programaci´n secuencial. o • Entender los conceptos de sincronizaci´n y exclusi´n mutua entre procesos. o o • Identificar las propiedades de seguridad y vivacidad que un sistema concurrente debe cumplir y ser capaz de razonar si dichas propiedades se cumplen. • Conocer los principales modelos de programaci´n concurrente, paralela y distribuida. o • Adquirir experiencia y conocimiento en los mecanismos de sincronizaci´n y comunicaci´n que se utilizan o o en la actualidad para desarrollar programas concurrentes tanto para sistemas de memoria compartida como para sistemas distribuidos. • Entender el funcionamiento de sem´foros y monitores como mecanismos de sincronizaci´n para memoria a o compartida y comprender c´mo se pueden resolver problemas de programaci´n concurrente usando o o monitores. creado October 4, 2013- p´gina 12 / 222 a
  • 13. SCD (13-14). Gu´ de la asignatura. ıa • Ser capaz de desarrollar algoritmos para sistemas basados en memoria compartida y para sistemas distribuidos que resuelvan problemas modelo en programaci´n concurrente. o • Conocer y ser capaz de usar bibliotecas y plataformas estandarizadas para la implementaci´n de o programas concurrentes basados en memoria compartida y para sistemas distribuidos • Conocer las t´cnicas m´s destacadas para el dise˜o de sistemas de tiempo real e a n Temario de teor´ ıa Se divide en los siguientes cap´ ıtulos: 1. Introducci´n a la Programaci´n Concurrente. o o 2. Algoritmos y mecanismos de sincronizaci´n basados en memoria compartida. o 3. Sistemas basados en paso de mensajes. 4. Introducci´n a los sistemas de tiempo real. o Temario de pr´cticas a Pr´cticas evaluables: a 1. Resoluci´n de problemas de sincronizaci´n con sem´foros. o o a 2. Programaci´n de monitores con hebras. o 3. Programaci´n de aplicaciones distribuidas. o 4. Programaci´n de tareas peri´dicas con prioridades. o o Seminarios impartidos presencialmente en las clases de pr´cticas: a 1. Introducci´n a la programaci´n mutihebra usando sem´foros. o o a 2. Introducci´n a la programaci´n mutihebra con monitores. o o 3. Introducci´n al uso de una interfaz de paso de mensajes. o 1.3 Metodolog´ docente y evaluaci´n ıa o Metodolog´ docente. ıa Dado el car´cter b´sico de la asignatura, se pretende que el alumno adquiera los conocimientos te´ricos a a o de la materia y los sepa aplicar con soltura. Para ello, las actividades de ense˜anza-aprendizaje que se n realizar´n ser´n una combinaci´n de: a a o • Actividades presenciales, entre las que se incluyen: ◾ Clases magistrales creado October 4, 2013- p´gina 13 / 222 a
  • 14. SCD (13-14). Gu´ de la asignatura. ıa ◾ Resoluci´n de ejercicios/problemas individuales y/o en grupo o ◾ Sesiones pr´cticas en laboratorio a ◾ Tutor´ ıas ◾ Pruebas objetivas • Actividades no presenciales, que pueden ser: ◾ Estudio individual o en grupo ◾ Realizaci´n de ejercicios/problemas/trabajos tanto individuales como en grupo o ◾ Confecci´n de la carpeta de aprendizaje o portafolio de pr´cticas. o a Evaluaci´n o Un papel importante del proceso de aprendizaje, es la evaluaci´n que tiene una doble misi´n: o o • Garantizar la adquisici´n de competencias o • Llevar a cabo una evaluaci´n formativa en la que se fomenta la continua retroalimentaci´n del alumno o o que puede conocer en todo momento c´mo va en su aprendizaje. Para ello, en todo momento: o ◾ Se resolver´n las pruebas objetivas, ejercicios, problemas, etc. a ◾ Se mantendr´ una carpeta de aprendizaje con todo el material generado en las pr´cticas de la a a asignatura. Esta carpeta muestra el proceso de aprendizaje en pr´cticas: res´menes, ejercicios y a u sus soluciones, dudas y sus respuestas, reflexiones, indagaciones y b´squeda bibliogr´fica, diario u a de clase, resultados de reuniones de grupo o tutor´ etc. La carpeta ser´ revisada al menos una ıas, a vez en tutor´ ıas. Calificaci´n o Los criterios b´sicos para obtener la calificaci´n son los siguientes: a o • La m´xima nota en teor´ y pr´cticas son 5 puntos en cada una. a ıa a • Para aprobar la asignatura es necesario tener una calificaci´n num´rica superior o igual a 5 (sobre o e 10), sumando teor´ y pr´cticas. ıa a • Adem´s del requisito anterior, se establece como requisito adicional para superar la asignatura que, a tanto la calificaci´n correspondiente a la parte te´rica como la correspondiente a la parte pr´ctica, o o a sean cada una mayores o iguales a 2 (sobre 5). Evaluaci´n de teor´ y/o pr´cticas ya superadas o ıa a Existen estas opciones: Para los alumnos que no logren aprobar la asignatura en la convocatoria ordinaria de febrero (o septiembre) del a˜o 2014 n Si el alumno obtiene una nota igual o superior a 2,5 en teor´ o pr´cticas, se podr´ guardar dicha nota ıa a a para la convocatoria de septiembre (o diciembre) del a˜o 2014. n creado October 4, 2013- p´gina 14 / 222 a
  • 15. SCD (13-14). Gu´ de la asignatura. ıa Para los alumnos que no logren aprobar la asignatura en el curso acad´mico 2013-14 e Si el alumno obtiene una nota igual o superior a 2,5 en pr´cticas con evaluaci´n continua, se podr´ guardar a o a dicha nota para todas las convocatorias del curso 2014-15. Modalidades de evaluaci´n o Los alumnos pueden seleccionar una de las siguientes dos modalidades de evaluaci´n: o • Evaluaci´n continuada y formativa: Basada en la asistencia regular a clases de teor´ y pr´cticas y o ıa a la realizaci´n de las actividades propuestas. o • Examen final: Basada en la realizaci´n de un examen escrito relativo al temario de teor´ y la defensa o ıa, de las pr´cticas ante el profesor de pr´cticas asignado al alumno. a a Evaluaci´n continuada y formativa o En esta modalidad, los alumnos tienen que asistir a clase regularmente y realizar las pruebas y ejercicios que se plantean a lo largo del curso. • Deben asistir a todas las pruebas objetivas de teor´ o pr´cticas. ıa a • Se admite que, de forma justificada, se falte a una prueba como m´ximo. a • Esta modalidad ser´ el mecanismo de evaluaci´n por defecto de todos los alumnos salvo para los que a o soliciten de forma justificada (y les sea concedida) la otra modalidad (evaluaci´n unica final) o ´ Calificaci´n de teor´ en evaluaci´n continua o ıa o La calificaci´n de teor´ (5 puntos) se reparte de la siguiente forma: o ıa • 4,5 puntos corresponden a 4 pruebas objetivas individuales realizadas al final de cada tema. La distribuci´n de la puntuaci´n por temas es la dada en la siguiente tabla: o o Tema Punt. m´x. a 1 0,7 2 1,8 3 1,6 4 0,4 Total 4,5 • 0,5 puntos correspondiente a la resoluci´n de ejercicios, problemas, y/o trabajos. o Calificaci´n de pr´cticas en evaluaci´n continua o a o La calificaci´n de pr´cticas (5 puntos) se obtiene de la siguiente forma: o a • 4,5 puntos correspondientes a cinco pruebas objetivas (pr´cticas 1, 2, 3, 4 y 5) que se realizan durante a la ultima sesi´n de pr´cticas de la parte a evaluar. Esta a su vez se distribuye como indica la siguiente ´ o a tabla: Tema Punt. m´x. a 1 1,2 2 1,5 3 1,3 4 0,5 Total 4,5 • 0,5 puntos de las soluciones de los ejercicios propuestos que sean presentadas en clase a los compa˜eros n o enviadas al profesor. La carpeta de aprendizaje podr´ ser revisada al menos una vez durante el cuatrimestre en tutor´ a ıas creado October 4, 2013- p´gina 15 / 222 a
  • 16. SCD (13-14). Gu´ de la asignatura. ıa Evaluaci´n por examen final o Para aquellos alumnos que hayan solicitado y les haya sido concedida la evaluaci´n por esta modalidad. o Consta de dos partes: • Examen de teor´ tendr´ lugar en la fecha fijada por el centro ıa: a • Defensa de las pr´cticas: tendr´n lugar en las fechas en las que se reserven para este fin las aulas a a de pr´cticas de la ETSIIT a 1.4 Bibliograf´ ıa Bibliograf´ fundamental (1/2) ıa • G. R. Andrews. Foundations of Multithreaded, Parallel, and Distributed Programming. Addison Wesley, 2000. • M. Ben-Ari. Principles of Concurrent and Distributed Programming. Prentice Hall, 2nd edition. 2006. • J. T. Palma, C. Garrido, F. S´nchez, A. Quesada. Programaci´n Concurrente. Thomson-Paraninfo. a o 2003. • G. R. Andrews. Concurrent Programming: Principles and Practice. Benjamin/Cummings, 1991. • F. Almeida, D. Gimenez, J. M. Mantas, A.M. Vidal. Introducci´n a la Programacion Paralela. Parano info Cengage Learning, 2008. Bibliograf´ fundamental (2/2) ıa • V. Kumar , A. Grama, A. Gupta, G. Karypis. Introduction to Parallel Computing. Benjamin/Cummings Publishing Company, 2003. • N. Santoro. Design and analysis of distributed algorithms. Wiley Series on parallel and distributed computing. 2007. • A. Burns, A. Wellings. Sistemas de Tiempo Real y Lenguajes de Programaci´n. (3a edici´n). Addison o o Wesley, 2003. • G.F. Coulouris, J. Dollimore, T. Kindberg Distributed Systems: Concepts and Design (5a editci´n). o Pearson, 2011. Bibliograf´ complementaria. ıa • N. Gehani, A.D. McGettrick. Concurrent Programming. International Computer Science Series. Addison-Wesley. 1988. • C. Hughes, T. Hughes. Professional Multicore Programming: Design and Implementation for C++ Developers. Wrox Programmer to Programmer. 2008. creado October 4, 2013- p´gina 16 / 222 a
  • 17. SCD (13-14). Gu´ de la asignatura. ıa • C. Breshears. The Art of Concurrency: A Thread Monkey´ Guide to Writing Parallel Applications. s ´ OReilly Media. 2009. • N.A. Lynch. Distributed Algorithms. Morgan Kaufmann. 1996. creado October 4, 2013- p´gina 17 / 222 a
  • 18. SCD (13-14). Gu´ de la asignatura. ıa creado October 4, 2013- p´gina 18 / 222 a
  • 19. Part II Apuntes de teor´ ıa 19
  • 21. Chapter 2 Tema 1. Introducci´n. o 2.1 2.1.1 Conceptos b´sicos y motivaci´n a o Conceptos b´sicos relacionados con la concurrencia a Programa concurrente, concurrencia y programaci´n concurrente o • Programa secuencial: Declaraciones de datos + Conjunto de instrucciones sobre dichos datos que se deben ejecutar en secuencia. • Programa concurrente: l´gicamente en paralelo. o Conjunto de programas secuenciales ordinarios que se pueden ejecutar • Proceso: Ejecuci´n de un programa secuencial. o • Concurrencia: Describe el potencial para ejecuci´n paralela, es decir, el solapamiento real o virtual o de varias actividades en el tiempo. • Programaci´n Concurrente (PC): Conjunto de notaciones y t´cnicas de programaci´n usadas para o e o expresar paralelismo potencial y resolver problemas de sincronizaci´n y comunicaci´n. o o • La PC es independiente de la implementaci´n del paralelismo. Es una abstracci´n o o Programaci´n paralela, programaci´n distribuida y programaci´n de tiempo real o o o • Programaci´n paralela: o Su principal objetivo es acelerar la resoluci´n de problemas concretos o mediante el aprovechamiento de la capacidad de procesamiento en paralelo del hardware disponible. • Programaci´n distribuida: Su principal objetivo es hacer que varios componentes software localizados o en diferentes ordenadores trabajen juntos. • Programaci´n de tiempo real: Se centra en la programaci´n de sistemas que est´n funcionando o o a continuamente, recibiendo entradas y enviando salidas a/desde componentes hardware (sistemas reactivos), en los que se trabaja con restricciones muy estrictas en cuanto a la respuesta temporal (sistemas de tiempo real). 21
  • 22. SCD (13-14). Tema 1. Introducci´n.. o 2.1.2 Motivaci´n de la Programaci´n concurrente o o Beneficios de la Programaci´n concurrente o La PC resulta m´s complicada que la programaci´n secuencial. a o ¿ Por qu´ es necesario conocer la Programaci´n Concurrente ? e o 1. Mejora de la eficiencia La PC permite aprovechar mejor los recursos hardware existentes. • En sistemas con un solo procesador: ◾ Al tener varias tareas, cuando la tarea que tiene el control del procesador necesita realizar una E/S cede el control a otra, evitando la espera ociosa del procesador. ◾ Tambi´n permite que varios usuarios usen el sistema de forma interactiva (actuales sistemas e operativos multisusuario). • En sistemas con varios procesadores: ◾ Es posible repartir las tareas entre los procesadores, reduciendo el tiempo de ejecuci´n. o ◾ Fundamental para acelerar complejos c´mputos num´ricos. o e Beneficios de la Programaci´n concurrente (2) o 2. Mejora de la calidad Muchos programas se entienden mejor en t´rminos de varios procesos secuenciales ejecut´ndose concure a rentemente que como un unico programa secuencial. ´ Ejemplos: • Servidor web para reserva de vuelos: Es m´s natural, considerar cada petici´n de usuario como a o un proceso e implementar pol´ ıticas para evitar situaciones conflictivas (permitir superar el l´ ımite de reservas en un vuelo). • Simulador del comportamiento de una gasolinera: Es m´s sencillo considerar los surtidores, clientes, a veh´ ıculos y empleados como procesos que cambian de estado al participar en diversas actividades comunes, que considerarlos como entidades dentro de un unico programa secuencial. ´ 2.2 2.2.1 Modelo abstracto y consideraciones sobre el hardware Consideraciones sobre el hardware Modelos de arquitecturas para programaci´n concurrente o creado October 4, 2013- p´gina 22 / 222 a
  • 23. SCD (13-14). Tema 1. Introducci´n.. o Mecanismos de implementaci´n de la concurrencia o • Dependen fuertemente de la arquitectura. • Consideran una m´quina virtual que representa un sistema (multiprocesador o sistema distribuido), a proporcionando base homog´nea para ejecuci´n de los procesos concurrentes. e o • El tipo de paralelismo afecta a la eficiencia pero no a la correcci´n. o Concurrencia en sistemas monoprocesador • Multiprogramaci´n: El sistema operativo gestiona c´mo m´ltiples procesos se reparten los ciclos de o o u CPU. • Mejor aprovechamiento CPU. • Servicio interactivo a varios usuarios. • Permite usar soluciones de dise˜o concurrentes. n • Sincronizaci´n y comunicaci´n mediante variables compartidas. o o creado October 4, 2013- p´gina 23 / 222 a
  • 24. SCD (13-14). Tema 1. Introducci´n.. o Concurrencia en multiprocesadores de memoria compartida • Los procesadores pueden compartir o no f´ ısicamente la misma memoria, pero comparten un espacio de direcciones compartido. • La interacci´n entre los procesos se puede implementar mediante variables alojadas en direccciones o del espacio compartido (variables compartidas). • Ejemplo: PCs con procesadores muticore. Concurrencia en sistemas distribuidos • No existe un memoria com´n: cada procesador tiene su espacio de direcciones privado. u • Los procesadores interaccionan transfiri´ndose datos a trav´s de una red de interconexi´n (paso de e e o mensajes). • Programaci´n distribuida: adem´s de la concurrencia, trata con otros problemas como el tratamiento o a de los fallos, transparencia, heterogeneidad, etc. • Ejemplos: Clusters de ordenadores, internet, intranet. creado October 4, 2013- p´gina 24 / 222 a
  • 25. SCD (13-14). Tema 1. Introducci´n.. o 2.2.2 Modelo Abstracto de concurrencia Sentencias at´micas y no at´micas o o Sentencia at´mica (indivisible) o Una sentencia o instrucci´n de un proceso en un programa concurrente es at´mica si siempre se ejecuta de o o principio a fin sin verse afectada (durante su ejecuci´n) por otras sentencias en ejecuci´n de otros procesos o o del programa. • No se ver´ afectada cuando el funcionamiento de dicha instrucci´n no dependa nunca de como se a o est´n ejecutando otras instrucciones. e • El funcionamiento de una instrucci´n se define por su efecto en el estado de ejecuci´n del programa o o justo cuando acaba. • El estado de ejecuci´n esta formado por los valores de las variables y los registros de todos los o procesos. Ejemplos de sentencias at´micas. o A modo de ejemplo de instrucciones at´micas, cabe citar muchas de las instrucciones m´quina del repertorio o a de un procesador, por ejemplo estas tres: • Leer una celda de memoria y cargar su valor en ese momento en un registro del procesador • Incrementar el valor de un registro (u otras operaciones aritm´ticas entre registros). e • Escribir el valor de un registro en una celda de memoria. El resultado de estas instrucciones no depende nunca de otras intrucciones que se est´n ejecutando cone currentemente. Al finalizar, la celda de memoria o el registro tomar´ un valor concreto predecible siempre a a partir del estado al inicio. • En el caso de la escritura en memoria, por ejemplo, el hardware asegura que el valor escrito(justo al final de la ejecuci´n) es siempre el que hab´ en el registro (justo al inicio de la ejecuci´n). o ıa o Ejemplos de sentencias no at´micas. o La mayor´ de las sentencias en lenguajes de alto nivel son t´ ıa ıpicamente no at´micas, por ejemplo, la sentencia o § ¦ x := x + 1 ; { incrementa el valor de la variable entera ’x’ (en RAM) en una unidad } Para ejecutarla , el compilador o int´rprete podr´ usar una secuencia de tres sentencias como esta: e ıa 1. leer el valor de x y cargarlo en un registro r del procesador 2. incrementar en un unidad el valor almacenado en el registro r 3. escribir el valor del registro r en la variable x El resultado (es decir, el valor que toma x justo al acabar) depende de que haya o no haya otras sentencias ejecut´ndose a la vez y escribiendo simult´neamente sobre la variable x. Podr´ ocurrir que el valor al final a a ıa no sea igual al valor al empezar m´s uno. a creado October 4, 2013- p´gina 25 / 222 a ¤ ¥
  • 26. SCD (13-14). Tema 1. Introducci´n.. o Interfoliaci´n de sentencias at´micas o o Supongamos que definimos un programa concurrente C compuesto de dos procesos secuenciales PA y PB que se ejecutan a la vez. La ejecuci´n de C puede dar lugar a cualquiera de las posibles mezclas (interfoliaciones) de sentencias o at´micas de PA y PB . o Pr. PA PB C C C C C Posibles secuencias de instr. at´micas o A1 A2 A3 A4 A5 B1 B2 B3 B4 B5 A1 A2 A3 A4 A5 B1 B2 B3 B4 B5 B1 B2 B3 B4 B5 A1 A2 A3 A4 A5 A1 B1 A2 B2 A3 B3 A4 B4 A5 B5 B1 B2 A1 B3 B4 A2 B5 A3 A4 A5 ⋯ las sentencias at´micas se ordenan en funci´n del instante en el que acaban (que es cuando tienen efecto) o o Abstracci´n o El modelo basado en el estudio de todas las posibles secuencias de ejecuci´n entrelazadas de los procesos o constituye una abstracci´n sobre las circunstancias de la ejecuci´n de los programas concurrentes, ya que: o o • Se consideran exclusivamente las caracter´ ısticas relevantes que determinan el resultado del c´lculo a • Esto permite simplificar el an´lisis o creaci´n de los programas concurrentes. a o Se ignoran los detalles no relevantes para el resultado, como por ejemplo: • las areas de memoria asignadas a los procesos ´ • los registros particulares que est´n usando a • el costo de los cambios de contexto entre procesos • la pol´ ıtica del S.O. relativa a asignaci´n de CPU o • las diferencias entre entornos multiprocesador o monoprocesador • .... Independencia del entorno de ejecuci´n o El entrelazamiento preserva la consistencia El resultado de una instrucci´n individual sobre un dato no depende de las circunstancias de la ejecuci´n. o o Supongamos que un programa P se compone de dos instrucciones at´micas, I0 e I1 , que se ejecutan concuro rentemente, P I0 I1 , entonces: creado October 4, 2013- p´gina 26 / 222 a
  • 27. SCD (13-14). Tema 1. Introducci´n.. o • Si I0 e I1 no acceden a la misma celda de memoria o registro, el orden de ejecuci´n no afecta al o resultado final. • Si I0 ≡ M ← 1 y I1 ≡ M ← 2, la unica suposici´n razonable es que el resultado sea consistente. Por ´ o tanto, al final M = 1 ´ M = 2, pero nunca por ejemplo M = 3. o En caso contrario, ser´ imposible razonar acerca de la correcci´n de los programas concurrentes. ıa o Velocidad de ejecuci´n de los procesos. Hip´tesis del progreso finito o o Progreso Finito No se puede hacer ninguna suposici´n acerca de las velocidades absolutas/relativas de ejecuci´n de los o o procesos, salvo que es mayor que cero. Un programa concurrente se entiende en base a sus componentes (procesos) y sus interacciones, sin tener en cuenta el entorno de ejecuci´n. o Ejemplo: Un disco es m´s lento que una CPU pero el programa no deber´ asumir eso en el dise˜o del a ıa n programa. Si se hicieran suposiciones temporales: • Ser´ dif´ detectar y corregir fallos ıa ıcil • La correcci´n depender´ de la configuraci´n de ejecuci´n, que puede cambiar o ıa o o Hip´tesis del progreso finito o Si se cumple la hip´tesis, la velocidad de ejecuci´n de cada proceso ser´ no nula, lo cual tiene estas dos o o a consecuencias: Punto de vista global Durante la ejecuci´n de un programa concurrente, en cualquier momento existir´ al menos 1 proceso o a preparado, es decir, eventualmente se permitir´ la ejecuci´n de alg´n proceso. a o u Punto de vista local Cuando un proceso concreto de un programa concurrente comienza la ejecuci´n de una sentencia, completar´ o a la ejecuci´n de la sentencia en un intervalo de tiempo finito. o Estados e historias de ejecuci´n de un programa concurrente o Estado de un programa concurrente Valores de las variables del programa en un momento dado. Incluyen variables declaradas expl´ ıcitamente y variables con informaci´n de estado oculta (contador del programa, registros,...). o Un programa concurrente comienza su ejecuci´n en un estado inicial y los procesos van modificando el o estado conforme se van ejecutando sus sentencias at´micas (producen transiciones entre dos estados de o forma indivisible). Historia o traza de un programa concurrente Secuencia de estados s0 → s1 → . . . → sn , producida por una secuencia concreta de interfoliaci´n. o creado October 4, 2013- p´gina 27 / 222 a
  • 28. SCD (13-14). Tema 1. Introducci´n.. o Notaciones para expresar ejecuci´n concurrente o • Propuestas Iniciales: no separan la definici´n de los procesos de su sincronizaci´n. o o • Posteriores Propuestas: separan conceptos e imponen estructura. • Declaraci´n de procesos: rutinas espec´ o ıficas de programaci´n concurrente o grama concurrente m´s clara. a ⇒ Estructura del pro- Sistemas Est´ticos a • N´mero de procesos fijado en el fuente del programa. u • Los procesos se activan al lanzar el programa • Ejemplo: Message Passing Interface (MPI-1). Sistemas Din´micos a • N´mero variable de procesos/hebras que se pueden activar en cualquier momento de la ejecuci´n. u o • Ejemplos: OpenMP, PThreads, Java Threads, MPI-2. Grafo de Sincronizaci´n o • Es un Grafo Dirigido Ac´ ıclico (DAG) donde cada nodo representa una secuencia de sentencias del programa (actividad). Dadas dos actividades, A y B, una arista conectando A en direcci´n hacia B o significa que B no puede comenzar su ejecuci´n hasta que A haya finalizado. o P0 P1 P3 P2 P5 P4 P6 P7 • Muestra las restricciones de precedencia que determinan cu´ndo una actividad puede empezar en un a programa. • Tiene que ser ac´ ıclico. creado October 4, 2013- p´gina 28 / 222 a
  • 29. SCD (13-14). Tema 1. Introducci´n.. o Definici´n est´tica de procesos o a El n´mero de procesos (arbitrario) y el c´digo que ejecutan no cambian entre ejecuciones. Cada proceso se u o asocia con su identificador y su c´digo mediante la palabra clave process o § var .... { vars. compartidas } ¤ process NomUno ; var .... { vars. locales } begin .... { codigo } end process NomDos ; var .... { vars. locales } begin .... { codigo } end ... { otros procesos } ¦ inicio NomUno NomDos fin ¥ el programa acaba cuando acaban todos los procesos. Las vars. compartidas se iniciaizan antes de comenzar ning´n proceso. u Definici´n est´tica de vectores de procesos o a Se pueden usar definiciones est´ticas de grupos de procesos similares que solo se diferencia en el valor de a una constante (vectores de procesos) § var .... { vars. compartidas } ¤ process NomP[ ind : a..b ] ; var .... { vars. locales } begin .... { codigo } .... { aqui ind vale a, a + 1,...,b } end ... ¦ { otros procesos } inicio NomP[a] .... NomP[b] fin ¥ • En cada caso, a y b se traducen por dos constantes concretas (el valor de a ser´ t´ a ıpicamente 0 o 1). • El n´mero total de procesos ser´ b − a + 1 (se supone que a <= b) u a Creaci´n de procesos no estructurada con fork-join. o • fork: sentencia que especifica que la rutina nombrada puede comenzar su ejecuci´n, al mismo tiempo o que comienza la sentencia siguiente (bifurcaci´n). o • join: sentencia que espera la terminaci´n de la rutina nombrada, antes de comenzar la sentencia o siguiente (uni´n). o creado October 4, 2013- p´gina 29 / 222 a
  • 30. SCD (13-14). Tema 1. Introducci´n.. o § procedure P1 ; begin A ; fork P2 ; B ; join P2 ; C ; end ¦ ¤ § procedure P2 ; begin D ; end ¦ ¤ A A fork B ¥ D B join D C C ¥ • Ventajas: pr´ctica y potente, creaci´n din´mica. a o a • Inconvenientes: no estructuraci´n, dif´ comprensi´n de los programas. o ıcil o Creaci´n de procesos estructurada con cobegin-coend o Las sentencias en un bloque delimitado por cobegin-coend comienzan su ejecuci´n todas ellas a la vez: o • en el coend se espera a que se terminen todas las sentencias. • Hace expl´ ıcito qu´ rutinas van a ejecutarse concurrentemente. e § begin A ; cobegin B ; C ; D ; coend E ; end ¦ ¤ A cobegin B C A D B E • Ventajas: impone estructura: 1 unica entrada y 1 unica salida ´ ´ • Inconveniente: menor potencia expresiva que fork-join. 2.3 D E coend ¥ C ⇒ m´s f´cil de entender. a a Exclusi´n mutua y sincronizaci´n o o Exclusi´n mutua y sincronizaci´n o o Seg´n el modelo abstracto, los procesos concurrentes ejecutan sus instrucciones at´micas de forma que, u o en principio, es completamente arbitrario el entremezclado en el tiempo de sus respectivas secuencias de instrucciones. Sin embargo, en un conjunto de procesos que no son independientes entre s´ (es decir, son ı cooperativos), algunas de las posibles formas de combinar las secuencias no son v´lidas. a • en general, se dice que hay una condici´n de sincronizaci´n cuando esto ocurre, es decir, que hay o o alguna restricci´n sobre el orden en el que se pueden mezclar las instrucciones de distintos procesos. o • un caso particular es la exclusi´n mutua, son secuencias finitas de instrucciones que un proceso debe o ejecutar de principio a fin sin mezclarse con otras (o las mismas) de otros procesos. creado October 4, 2013- p´gina 30 / 222 a
  • 31. SCD (13-14). Tema 1. Introducci´n.. o 2.3.1 Concepto de exclusi´n mutua o Exclusi´n mutua o La restricci´n se refiere a una o varias secuencias de instrucciones consecutivas que aparecen en el texto de o uno o varios procesos. • Al conjunto de dichas secuencias de instrucciones se le denomina secci´n cr´ o ıtica (SC). • Ocurre exclusi´n mutua (EM) cuando los procesos solo funcionan correctamente si, en cada instante o de tiempo, hay como mucho uno de ellos ejecutando cualquier instrucci´n de la secci´n cr´ o o ıtica. es decir, el solapamiento de las instrucciones debe ser tal que cada secuencia de instrucciones de la SC se ejecuta como mucho por un proceso de principio a fin, sin que (durante ese tiempo) otros procesos ejecuten ninguna de esas instrucciones ni otras de la misma SC. Ejemplos de exclusi´n mutua o El ejemplo t´ ıpico de EM ocurre en procesos con memoria compartida que acceden para leer y modificar variables o estructuras de datos comunes usando operaciones no at´micas (es decir, compuestas de varias o instrucciones m´quina o elementales que pueden solaparse con otras secuencias), aunque hay muchos otros a ejemplos: • env´ de datos a dispositivos que no se pueden compartir (p.ej., el bucle que env´ una secuencia de ıo ıa datos que forma un texto a una impresora o cualquier otro dispositivo de salida v´ el bus del sistema). ıa • recepci´n de datos desde dispositivos (p.ej., un bucle que lee una secuencia de pulsaciones de teclas o desde el teclado, tambi´n a trav´s del bus). e e Un ejemplo sencillo de exclusi´n mutua o Para ilustrar el problema de la EM, veremos un ejemplo sencillo que usa una variable entera (x) en memoria compartida y operaciones aritm´ticas elementales. e • La secci´n cr´ o ıtica esta formada por todas las secuencias de instrucciones m´quina que se obtienen al a traducir (compilar) operaciones de escritura (o lectura y escritura) de la variable (p.ej., asignaciones como x:=x+1 o x:=4∗z). • Veremos que si varios procesos ejecutan las instrucciones m´quina de la secci´n cr´ a o ıtica de forma simult´nea, los resultados de este tipo de asignaciones son indeterminados. a aqu´ el t´rmino indeterminado indica que para cada valor de x (o del resto de variables) previo a cada ı, e asignaci´n, existe un conjunto de valores distintos posibles de x al finalizar la ejecuci´n de dicha asignaci´n o o o (el valor concreto que toma x depende del orden de entremezclado de las instrucciones m´quina). a Traducci´n y ejecuci´n de asignaciones o o Si consideramos la instrucci´n x:=x+1 (que forma la SC), veremos que una traducci´n t´ o o ıpica a c´digo o m´quina tendr´ estas tres instrucciones: a ıa creado October 4, 2013- p´gina 31 / 222 a
  • 32. SCD (13-14). Tema 1. Introducci´n.. o 1. load ri ← x 3. store ri → x 2. add ri , 1 cargar el valor de la variable x en un registro r de la CPU (por el proceso n´mero i). u incrementar en una unidad el valor del registro r guardar el valor del registro r en la posici´n de memoria de la vario able x. • hay dos procesos concurrentes (P0 y P1 ) que ejecutan la asignaci´n, y por tanto las tres instrucciones o m´quina se pueden entremezclar de forma arbitraria. a • cada proceso mantiene su propia copia del registro r (los llamaremos r0 y r1 ) • ambos comparten x, cuyos accesos v´ load y store son at´micos pues bloquean el bus del sistema. ıa o Posibles secuencias de instrucciones Suponemos que inicialmente x vale 0 y ambos procesos ejecutan la asignaci´n, puede haber varias secuencias o de interfoliaci´n, aqu´ vemos dos: o ı P0 load r0 ← x add r0 , 1 store r0 → x P1 load r1 ← x add r1 , 1 store r1 → x x 0 0 1 1 1 2 P0 load r0 ← x add r0 , 1 store r0 → x P1 load r1 ← x add r1 , 1 store r1 → x x 0 0 0 0 1 1 por tanto, partiendo de x== 0, tenemos al final que la variable puede tomar el valor 1 o 2 dependiendo del orden de ejecuci´n de las instrucciones. o 2.3.2 Condici´n de sincronizaci´n o o Condici´n de sincronizaci´n. o o En general, en un programa concurrente compuesto de varios procesos, una condici´n de sincronizaci´n o o establece que: no son correctas todas las posibles interfoliaciones de las secuencias de instrucciones at´micas o de los procesos. • esto ocurre t´ ıpicamente cuando, en un punto concreto de su ejecuci´n, uno o varios procesos deben o esperar a que se cumpla una determinada condici´n global (depende de varios procesos). o Veremos un ejemplo sencillo de condici´n de sincronizaci´n en el caso en que los procesos puedan usar o o variables comunes para comunicarse (memoria compartida). En este caso, los accesos a las variables no pueden ordenarse arbitrariamente (p.ej.: leer de ella antes de que sea escrita) creado October 4, 2013- p´gina 32 / 222 a
  • 33. SCD (13-14). Tema 1. Introducci´n.. o Ejemplo de sincronizaci´n. Productor Consumidor o Un ejemplo t´ ıpico es el de dos procesos cooperantes en los cuales uno de ellos (productor) produce una secuencia de valores (p.ej. enteros) y el otro (consumidor) usa cada uno de esos valores. La comunicaci´n o se hace v´ la variable compartida x.: ıa § { variables compartidas } var x : integer ; { contiene cada valor producido } ¦ § { Proceso productor: calcula ’ x ’ } process Productor ; var a : integer ; { no compartida } begin while true do begin { calcular un valor } a := ProducirValor() ; { escribir en mem. compartida } x := a ; { sentencia E } end end ¦ ¤ § { Proceso Consumidor: lee ’ x ’ } process Consumidor ; var b : integer ; { no compartida } begin while true do begin { leer de mem. compartida } b := x ; { sentencia L } { utilizar el valor leido } UsarValor(b) ; end end ¥ ¦ Secuencias correctas e incorrectas Los procesos descritos solo funcionan como se espera si el orden en el que se entremezclan las sentencias elementales etiquetadas como E (escritura) y L (lectura) es: E, L, E, L, E, L, . . .. • L, E, L, E, . . . es incorrecta: se hace una lectura de x previa a cualquier escritura (se lee valor indeterminado). • E, L, E, E, L, . . . es incorrecta: hay dos escrituras sin ninguna lectura entre ellas (se produce un valor que no se lee). • E, L, L, E, L, . . . es incorrecta: hay dos lecturas de un mismo valor, que por tanto es usado dos veces. La secuencia v´lida asegura la condici´n de sincronizaci´n: a o o • Consumidor no lee hasta que Productor escriba un nuevo valor en x (cada valor producido es usado una sola vez). • Productor no escribe un nuevo valor hasta que Consumidor lea el ultimo valor almacenado en x (ning´n ´ u valor producido se pierde). 2.4 2.4.1 Propiedades de los sistemas concurrentes Correcci´n de un sistema concurrente o Concepto de correcci´n de un programa concurrente o Propiedad de un programa concurrente: Atributo del programa que es cierto para todas las posibles secuencias de interfoliaci´n (historias del programa). o creado October 4, 2013- p´gina 33 / 222 a ¤ ¥ ¤ ¥
  • 34. SCD (13-14). Tema 1. Introducci´n.. o Hay 2 tipos: • Propiedad de seguridad (safety). • Propiedad de vivacidad (liveness). 2.4.2 Propiedades de seguridad y vivacidad Propiedades de Seguridad (Safety) • Son condiciones que deben cumplirse siempre del tipo: Nunca pasar´ nada malo. a • Requeridas en especificaciones est´ticas del programa. a • Similar a correcci´n parcial en programas secuenciales: “Si el programa termina, las respuestas deben o ser correctas. • Son f´ciles de demostrar y para cumplirlas se suelen restringir las posibles interfoliaciones. a Ejemplos: • Exclusi´n mutua: 2 procesos nunca entrelazan ciertas subsecuencias de operaciones. o • Ausencia Interbloqueo (Deadlock-freedom): Nunca ocurrir´ que los procesos se encuentren esperando a algo que nunca suceder´. a • Propiedad de seguridad en el Productor-Consumidor El consumidor debe consumir todos los datos producidos por el productor en el orden en que se van produciendo. Propiedades de Vivacidad (Liveness) • Deben cumplirse eventualmente. • Son propiedades din´micas dif´ a ıciles de probar: Realmente sucede algo bueno Ejemplos: • Ausencia de inanici´n (starvation-freedom): Un proceso o grupo de procesos no puede ser indefinidao mente pospuesto. En alg´n momento, podr´ avanzar. u a • Equidad (fairness): Tipo particular de prop. de vivacidad. Un proceso que desee progresar debe hacerlo con justicia relativa con respecto a los dem´s. M´s ligado a la implementaci´n y a veces a a o incumplida: existen distintos grados. creado October 4, 2013- p´gina 34 / 222 a
  • 35. SCD (13-14). Tema 1. Introducci´n.. o 2.5 2.5.1 Verificaci´n de programas concurrentes o Verificaci´n de programas concurrentes. Introducci´n o o Verificaci´n de programas concurrentes. Introducci´n o o ¿ C´mo demostrar que un programa cumple una determinada propiedad ? o • Posibilidad: realizar diferentes ejecuciones del programa y comprobar que se verifica la propiedad. • Problema: S´lo permite considerar un n´mero limitado de historias de ejecuci´n y no demuestra que o u o no existan casos indeseables. • Ejemplo: Comprobar que el proceso P produce al final x = 3: § process P ; var x : integer := 0 ; cobegin x := x+1 ; x := x+2 ; coend ¦ ¤ ¥ Hay varias historias que llevan a x==1 o x==2 (la asignaci´n no es at´mica), pero estas historias o o podr´ no aparecer dentro de un n´mero limitado de ejecuciones. ıan u Verificaci´n de programas concurrentes. Enfoque operacional o • Enfoque operacional: An´lisis exhaustivo de casos. Se chequea la correcci´n de todas las posibles a o historias. • Problema: Su utilidad est´ muy limitada cuando se aplica a programas concurrentes complejos ya que a el n´mero de interfoliaciones crece exponencialmente con el n´mero de instrucciones de los procesos. u u • Para el sencillo programa P (2 procesos, 3 sentencias at´micas por proceso) habr´ que estudiar 20 o ıa historias disferentes. 2.5.2 Enfoque axiom´tico para la verificaci´n a o Verificaci´n. Enfoque axiom´tico o a • Se define un sistema l´gico formal que permite establecer propiedades de programas en base a axiomas o y reglas de inferencia. • Se usan f´rmulas l´gicas (asertos) para caracterizar un conjunto de estados. o o • Las sentencias at´micas act´an como transformadores de predicados (asertos). Los teoremas en la o u l´gica tienen la forma: o creado October 4, 2013- p´gina 35 / 222 a
  • 36. SCD (13-14). Tema 1. Introducci´n.. o {P} S {Q} “Si la ejecuci´n de la sentencia S empieza en alg´n estado que hace verdadero el predicado P (preo u condici´n), entonces el predicado Q (poscondici´n) ser´ verdadero en el estado resultante. o o a • Menor Complejidad: El trabajo que conlleva la prueba de correcci´n es proporcional al n´mero de o u sentencias at´micas en el programa. o Invariante global • Invariante global: Predicado que referencia variables globales siendo cierto en el estado inicial de cada proceso y manteni´ndose cierto ante cualquier asignaci´n dentro de los procesos. e o • En una soluci´n correcta del Productor-Consumidor, un invariante global ser´ o ıa: consumidos ≤ producidos ≤ consumidos + 1 Bibliograf´ del tema 1. ıa Para m´s informaci´n, ejercicios, bibliograf´ adicional, se puede consultar: a o ıa 1.1. Conceptos b´sicos y Motivaci´n Palma (2003), cap´ a o ıtulo 1. 1.2. Modelo abstracto y Consideraciones sobre el hardware Ben-Ari (2006), cap´ ıtulo 2. Andrews (2000) cap´ ıtulo 1. Palma (2003) cap´ ıtulo 1. 1.3. Exclusi´n mutua y sincronizaci´n Palma (2003), cap´ o o ıtulo 1. 1.4. Propiedades de los Sistemas Concurrentes Palma (2003), cap´ ıtulo 1. 1.5. Verificaci´n de Programas concurrentes Andrews (2000), cap´ o ıtulo 2. 2.6 1 Problemas del tema 1. Considerar el siguiente fragmento de programa para 2 procesos P1 y P2 : Los dos procesos pueden ejecutarse a cualquier velocidad. ¿ Cu´les son los posibles valores resultantes para a x ?. Suponer que x debe ser cargada en un registro para incrementarse y que cada proceso usa un registro diferente para realizar el incremento. creado October 4, 2013- p´gina 36 / 222 a
  • 37. SCD (13-14). Tema 1. Introducci´n.. o § { variables compartidas } var x : integer := 0 ; ¦ § process P1 ; var i : integer ; begin for i := 1 to 2 do begin x := x+1 ; end end ¦ ¤ ¤ § process P2 ; var j : integer ; begin for j := 1 to 2 do begin x := x+1 ; end end ¥ ¦ ¥ ¤ ¥ 2 ¿ C´mo se podr´ hacer la copia del fichero f en otro g, de forma concurrente, utilizando la instrucci´n o ıa o concurrente cobegin-coend ? . Para ello, suponer que: • los archivos son secuencia de items de un tipo arbitrario T, y se encuentran ya abiertos para lectura (f) y escritura (g). Para leer un ´ ıtem de f se usa la llamada a funci´n leer(f) y para saber si se han o le´ todos los ´ ıdo ıtems de f, se puede usar la llamada fin(f) que devuelve verdadero si ha habido al menos un intento de leer cuando ya no quedan datos. Para escribir un dato x en g se puede usar la llamada a procedimiento escribir(g,x). • El orden de los ´ ıtems escritos en g debe coincidir con el de f. • Dos accesos a dos archivos distintos pueden solaparse en el tiempo. 3 Construir, utilizando las instrucciones concurrentes cobegin-coend y fork-join, programas concurrentes que se correspondan con los grafos de precedencia que se muestran a continuaci´n: o creado October 4, 2013- p´gina 37 / 222 a
  • 38. SCD (13-14). Tema 1. Introducci´n.. o 4 Dados los siguientes fragmentos de programas concurrentes, obtener sus grafos de precedencia asociados: § begin P0 ; cobegin P1 ; P2 ; cobegin P3 ; P4 ; P5 ; P6 ; coend P7 ; coend P8; end ¦ ¤ § begin P0 ; cobegin begin cobegin P1;P2; coend P5; end begin cobegin P3;P4; ¥ coend P6; end coend P7 ; end ¦ ¤ ¥ 5 Suponer un sistema de tiempo real que dispone de un captador de impulsos conectado a un contador de energ´ el´ctrica. La funci´n del sistema consiste en contar el n´mero de impulsos producidos en 1 hora ıa e o u (cada Kwh consumido se cuenta como un impulso) e imprimir este n´mero en un dispositivo de salida. Para u ello se ha de escribir un programa concurrente con 2 procesos: un proceso acumulador (lleva la cuenta de los impulsos recibidos) y un proceso escritor (escribe en la impresora). En la variable com´n a los 2 procesos u n se lleva la cuenta de los impulsos. Suponiendo que el sistema se encuentra en un estado correspondiente al valor de la variable n = N y en estas condiciones se presentan simult´neamente un nuevo impulso y el a final del periodo de 1 hora, obtener las posibles secuencias de ejecuci´n de los procesos y cu´les de ellas o a son correctas. Suponer que el proceso acumulador puede invocar un procedimiento Espera_impulso para esperar a que llegue un impulso, y que el proceso escritor puede llamar a Espera_fin_hora para esperar a que termine una hora. En el enunciado se usan sentencias de acceso a la variable n encerradas entre los s´ ımbolos < y >. Esto significa que cada una de esas sentencias se ejecuta en exclusi´n mutua entre los dos procesos, es decir, o esas sentencias se ejecutan de principio a fin sin entremezclarse entre ellas. creado October 4, 2013- p´gina 38 / 222 a
  • 39. SCD (13-14). Tema 1. Introducci´n.. o 6 Supongamos que tenemos un vector a en memoria compartida (de tama˜o par, es decir de tama˜o 2n para n n alg´n n > 1), y queremos obtener en otro vector b una copia ordenada de a. Podemos usar una llamada a u procedimiento de la forma sort(s,t) para ordenar un segmento de a (el que va desde s hasta t, ambos incluidos) de dos formas: (a) para ordenar todo el vector de forma secuencial con sort(1,2n);b:=a o bien (b) para ordenar las dos mitades de a de forma concurrente, y despu´s mezclar dichas dos mitades en un e segundo vector b (para mezclar usamos un procedimiento merge). A continuaci´n se encuentra una posible o versi´n del c´digo: o o § ¤ var a,b : array[1..2*n] of integer ; { n es una constante predefinida } var uc : array[1..2] of integer ; { ultimo completado de cada mitad } ¦ ¥ § ¤ § ¤ procedure Secuencial() ; { ordena el segmento de a entre s y t } var i : integer ; begin procedure Sort( mitad, s, t : integer ) Sort(1,1,2n) ; {ord. a} var i, j : integer ; for i := 1 to 2*n do {copia a en b} begin b[i] := a[i] ; for i := s to t do begin end for j:= s+1 to t do procedure Concurrente() ; if a[i] <= a[j] then begin swap( a[i], b[j] ) ; cobegin uc[mitad] := i ; Sort(1,1,n-1); end Sort(2,n,2*n); end ¦ ¥ coend Merge(1,n+1,2*n); end ¦ ¥ El c´digo de Merge se encarga de ir leyendo las dos mitades y en cada paso seleccionar el menor elemento o de los dos siguientes por leer en a (uno en cada mitad), y escribir dicho menor elemento en el vector mezclado b. El c´digo es el siguiente: o creado October 4, 2013- p´gina 39 / 222 a
  • 40. SCD (13-14). Tema 1. Introducci´n.. o § procedure Merge( inferior, medio, superior: integer ) ; var k, c1, c2, ind1, ind2 : integer; begin { k es la siguiente posicion a escribir en b } k:=1 ; { c1 y c2 indican siguientes elementos a mezclar en cada mitad } c1 := inferior ; c2 := medio ; { mientras no haya terminado con la primera mitad } while c1 < medio do begin if a[c1] < a[c2] then begin { minimo en la primera mitad } b[k] := a[c1] ; k := k+1 ; c1 := c1+1 ; if c1 >= medio then { Si fin prim. mitad, copia la segunda } for ind2 := c2 to superior do begin b[k] := a[ind2] ; k := k+1 ; end end else begin { minimo en la segunda mitad } b[k] := a[c2] ; k := k+1 ; c2 := c2+1 ; if c2 >= superior then begin { Si fin segunda mitad, copia primera } for ind1 := c1 to medio do begin b[k] := a[ind2] ; k:=k+1; end c1 := medio ; { fuerza terminacion del while } end end end end ¦ ¤ ¥ Llamaremos Ts (k) al tiempo que tarda el procedimiento Sort cuando actua sobre un segmento del vector con k entradas. Suponemos que el tiempo que (en media) tarda cada iteraci´n del bucle interno que hay en o Sort es la unidad (por definici´n). Es evidente que ese bucle tiene k(k − 1)/2 iteraciones, luego: o Ts (k) = k(k − 1) 2 = 1 2 1 k − k 2 2 El tiempo que tarda la versi´n secuencial sobre 2n elementos (llamaremos S a dicho tiempo) ser´ evidenteo a mente Ts (2n), luego 1 1 S = Ts (2n) = (2n)2 − (2n) = 2n2 − n 2 2 con estas definiciones, calcula el tiempo que tardar´ la versi´n paralela, en dos casos: a o (1) Las dos instancias concurrentes de Sort se ejecutan en el mismo procesador (llamamos P1 al tiempo que tarda). creado October 4, 2013- p´gina 40 / 222 a
  • 41. SCD (13-14). Tema 1. Introducci´n.. o (2) Cada instancia de Sort se ejecuta en un procesador distinto (lo llamamos P2 ) escribe una comparaci´n cualitativa de los tres tiempos (S,P1 y P2 ). o Para esto, hay que suponer que cuando el procedimiento Merge actua sobre un vector con p entradas, tarda p unidades de tiempo en ello, lo cual es razonable teniendo en cuenta que en esas circunstancias Merge copia p valores desde a hacia b. Si llamamos a este tiempo Tm (p), podemos escribir Tm (p) = p . 7 Supongamos que tenemos un programa con tres matrices (a,b y c) de valores flotantes declaradas como variables globales. La multiplicaci´n secuencial de a y b (almacenando el resultado en c) se puede hacer o mediante un procedimiento MultiplicacionSec declarado como aparece aqu´ ı: § var a, b, c : array[1..3,1..3] of real ; procedure MultiplicacionSec() var i,j,k : integer ; begin for i := 1 to 3 do for j := 1 to 3 do begin c[i,j] := 0 ; for k := 1 to 3 do c[i,j] := c[i,j] + a[i,k]*b[k,j] ; end end ¦ ¤ ¥ Escribir un programa con el mismo fin, pero que use 3 procesos concurrentes. Suponer que los elementos de las matrices a y b se pueden leer simult´neamente, as´ como que elementos distintos de c pueden escribirse a ı simult´neamente. a 8 Un trozo de programa ejecuta nueve rutinas o actividades (P1 , P2 , . . . , P9 ), repetidas veces, de forma concurrentemente con cobegin coend (ver la figura de la izquierda), pero que requieren sincronizarse seg´n u determinado grafo (ver la figura de la derecha): creado October 4, 2013- p´gina 41 / 222 a
  • 42. SCD (13-14). Tema 2. Sincronizaci´n en memoria compartida.. o Trozo de programa: § while true do cobegin P1 ; P2 ; P3 ; P4 ; P5 ; P6 ; P7 ; P8 ; P9 ; coend ¦ Grafo de sincronizaci´n: o ¤ P11 P P33 P P44 P ¥ P22 P P55 P P66 P P77 P P88 P P99 P Sup´n que queremos realizar la sincronizaci´n indicada en el grafo, usando para ello llamadas desde cada o o rutina a dos procedimientos (EsperarPor y Acabar). Se dan los siguientes hechos: • El procedimiento EsperarPor(i) es llamado por una rutina cualquiera (la n´mero k) para esperar a u que termine la rutina n´mero i, usando espera ocupada. Por tanto, se usa por la rutina k al inicio u para esperar la terminaci´n de las otras rutinas que corresponda seg´n el grafo. o u • El procedimiento Acabar(i) es llamado por la rutina n´mero i, al final de la misma, para indicar que u dicha rutina ya ha finalizado. • Ambos procedimientos pueden acceder a variables globales en memoria compartida. • Las rutinas se sincronizan unica y exclusivamente mediante llamadas a estos procedimientos, siendo ´ la implementaci´n de los mismos completamente transparente para las rutinas. o Escribe una implementaci´n de EsperarPor y Acabar (junto con la declaraci´n e inicializaci´n de las o o o variables compartidas necesarias) que cumpla con los requisitos dados. creado October 4, 2013- p´gina 42 / 222 a
  • 43. Chapter 3 Tema 2. Sincronizaci´n en memoria o compartida. 3.1 Introducci´n a la sincronizaci´n en memoria compartida. o o Sincronizaci´n en memoria compartida o En esta tema estudiaremos soluciones para exclusi´n mutua y sincronizaci´n basadas en el uso de memoria o o compartida entre los procesos involucrados. Este tipo de soluciones se pueden dividir en dos categor´ ıas: • Soluciones de bajo nivel con espera ocupada est´n basadas en programas que contienen expl´ a ıcitamente instrucciones de bajo nivel para lectura y escritura directamente a la memoria compartida, y bucles para realizar las esperas. • Soluciones de alto nivel partiendo de las anteriores, se dise˜a una capa software por encima que n ofrece un interfaz para las aplicaciones. La sincronizaci´n se consigue bloqueando un proceso cuando o deba esperar. Soluciones de bajo nivel con espera ocupada Cuando un proceso debe esperar a que ocurra un evento o sea cierta determinada condici´n, entra en un o bucle indefinido en el cual continuamente comprueba si la situaci´n ya se da o no (a esto se le llama espera o ocupada). Este tipo de soluciones se pueden dividir en dos categor´ ıas: • Soluciones software: se usan operaciones est´ndar sencillas de lectura y escritura de datos simples a (t´ ıpicamente valores l´gicos o enteros) en la memoria compartida o • Soluciones hardware (cerrojos): basadas en la existencia de instrucciones m´quina espec´ a ıficas dentro del repertorio de instrucciones de los procesadores involucrados Soluciones de alto nivel Las soluciones de bajo nivel con espera ocupada se prestan a errores, producen algoritmos complicados y tienen un impacto negativo en la eficiencia de uso de la CPU (por los bucles). En las soluciones de alto nivel se ofrecen interfaces de acceso a estructuras de datos y adem´s se usa bloqueo de procesos en lugar a de espera ocupada. Veremos algunas de estas soluciones: 43
  • 44. SCD (13-14). Tema 2. Sincronizaci´n en memoria compartida.. o • Sem´foros: se construyen directamente sobre las soluciones de bajo nivel, usando adem´s servicios a a del SO que dan la capacidad de bloquear y reactivar procesos. • Regiones cr´ ıticas condicionales: son soluciones de m´s alto nivel que los sem´foros, y que se pueden a a implementar sobre ellos. • Monitores: son soluciones de m´s alto nivel que las anteriores y se pueden implementar en algunos a lenguajes orientados a objetos como Java o Python. 3.1.1 Estructura de los procesos con Secciones Cr´ ıticas Entrada y salida en secciones cr´ ıticas Para analizar las soluciones a EM asumimos que un proceso que incluya un bloque considerado como secci´n o cr´ ıtica (SC) tendr´ dicho bloque estructurado en tres etapas: a 1. protocolo de entrada (PE): una serie de instrucciones que incluyen posiblemente espera, en los casos en los que no se pueda conceder acceso a la secci´n cr´ o ıtica. 2. secci´n cr´ o ıtica (SC): instrucciones que solo pueden ser ejecutadas por un proceso como mucho. 3. protocolo de salida (PS): instrucciones que permiten que otros procesos puedan conocer que este proceso ha terminado la secci´n cr´ o ıtica. Todas las sentencias que no forman parte de ninguna de estas tres etapas se denominan resto de sentencias (RS) . Acceso repetitivo a las secciones cr´ ıticas En general, un proceso puede contener m´s de una secci´n cr´ a o ıtica, y cada secci´n cr´ o ıtica puede estar desglosada en varios bloques de c´digo separados en el texto del proceso. Para simplificar el an´lisis, o a suponemos, sin p´rdida de generalidad, que: e • Cada proceso tiene una unica secci´n cr´ ´ o ıtica. • Dicha secci´n cr´ o ıtica est´ formada por un unico bloque contiguo de instrucciones. a ´ • El proceso es un bucle infinito que ejecuta en cada iteracci´n dos pasos: o ◾ Secci´n cr´ o ıtica (con el PE antes y el PS despu´s) e ◾ Resto de sentencias: se emplea un tiempo arbitrario no acotado, e incluso el proceso puede finalizar en esta secci´n, de forma prevista o imprevista. o de esta forma se prevee el caso m´s general en el cual no se supone nada acerca de cuantas veces un a proceso puede intentar entrar en una SC. creado October 4, 2013- p´gina 44 / 222 a
  • 45. SCD (13-14). Tema 2. Sincronizaci´n en memoria compartida.. o Condiciones sobre el comportamiento de los procesos. Para que se puedan implementar soluciones correctas al problema de EM, es necesario suponer que: Los procesos siempre terminan una secci´n cr´ o ıtica y emplean un intervalo de tiempo finito desde que la comienzan hasta que la terminan. es decir, durante el tiempo en que un proceso se encuentra en una secci´n cr´ o ıtica nunca • Finaliza o aborta. • Es finalizado o abortado externamente. • Entra en un bucle infinito. • Es bloqueado o suspendido indefinidamente de forma externa. en general, es deseable que el tiempo empleado en las secciones cr´ ıticas sea el menor posible, y que las instrucciones ejecutadas no puedan fallar. 3.1.2 Propiedades para exclusi´n mutua o Propiedades requeridas para las soluciones a EM Para que un algoritmo para EM sea correcto, se deben cumplir cada una de estas tres propiedades m´ ınimas: 1. Exclusi´n mutua o 2. Progreso 3. Espera limitada adem´s, hay propiedades deseables adicionales que tambi´n deben cumplirse: a e 4. Eficiencia 5. Equidad si bien consideramos correcto un algoritmo que no sea muy eficiente o para el que no pueda demostrarse claramente la equidad. Exclusi´n mutua o Es la propiedad fundamental para el problema de la secci´n cr´ o ıtica. Establece que En cada instante de tiempo, y para cada secci´n cr´ o ıtica existente, habr´ como mucho un proceso a ejecutando alguna sentencia de dicha regi´n cr´ o ıtica. En esta secci´n veremos soluciones de memoria compartida que permiten un unico proceso en una secci´n o ´ o cr´ ıtica. Si bien esta es la propiedad fundamental, no puede conseguirse de cualquier forma, y para ello se establecen las otras dos condiciones m´ ınimas que vemos a continuaci´n. o creado October 4, 2013- p´gina 45 / 222 a
  • 46. SCD (13-14). Tema 2. Sincronizaci´n en memoria compartida.. o Progreso Consideremos una secci´n cr´ o ıtica en un instante en el cual no hay ning´n proceso ejecut´ndola, pero s´ hay u a ı uno o varios procesos en el PE compitiendo por entrar a la SC. La propiedad de progreso establece que Un algoritmo de EM debe estar dise˜ado de forma tal que n 1. Despu´s de un intervalo de tiempo finito desde que ingres´ el primer proceso al PE, uno e o de los procesos en el mismo podr´ acceder a la SC. a 2. La selecci´n del proceso anterior es completamente independiente del comportamiento de o los procesos que durante todo ese intervalo no han estado en SC ni han intentado acceder. Cuando la condici´n (1) no se da, se dice que ocurre un interbloqueo, ya que todos los procesos en el PE o quedan en espera ocupada indefinidamente sin que ninguno pueda avanzar. Espera limitada Supongamos que un proceso emplea un intervalo de tiempo en el PE intentando acceder a una SC. Durante ese intervalo de tiempo, cualquier otro proceso activo puede entrar un n´mero arbitrario de veces n a ese u mismo PE y lograr acceso a la SC (incluyendo la posibilidad de que n = 0). La propiedad establece que: Un algoritmo de exclusi´n mutua debe estar dise˜ado de forma que n nunca ser´ superior a un o n a valor m´ximo determinado. a esto implica que las esperas en el PE siempre ser´n finitas (suponiendo que los procesos emplean un tiempo a finito en la SC). Propiedades deseables: eficiencia y equidad. Las propiedades deseables son estas dos: • Eficiencia Los protocolos de entrada y salida deben emplear poco tiempo de procesamiento (excluyendo las esperas ocupadas del PE), y las variables compartidas deben usar poca cantidad de memoria. • Equidad En los casos en que haya varios procesos compitiendo por acceder a una SC (de forma repetida en el tiempo), no deber´ existir la posibilidad de que sistem´ticamente se perjudique a ıa a algunos y se beneficie a otros. 3.2 Soluciones software con espera ocupada para E.M. Introducci´n o En esta secci´n veremos diversas soluciones para lograr exclusi´n mutua en una secci´n cr´ o o o ıtica usando variables compartidas entre los procesos o hebras involucrados. Estos algoritmos usan dichas variables para hacer espera ocupada cuando sea necesario en el protocolo de entrada. Los algoritmos que resuelven este problema no son triviales, y menos para m´s de dos procesos. En la a actualidad se conocen distintas soluciones con distintas propiedades. Veremos estos algoritmos: creado October 4, 2013- p´gina 46 / 222 a
  • 47. SCD (13-14). Tema 2. Sincronizaci´n en memoria compartida.. o • Algoritmo de Dekker (para 2 procesos) • Algoritmo de Peterson (para 2 y para un n´mero arbitrario de procesos). u 3.2.1 Refinamiento sucesivo de Dijkstra Introducci´n al refinamiento sucesivo de Dijkstra o El Refinamiento sucesivo de Dijskstra hace referencia a una serie de algoritmos que intentan resolver el problema de la exclusi´n mutua. o • Se comienza desde una versi´n muy simple, incorrecta (no cumple alguna de las propiedades), y o se hacen sucesivas mejoras para intentar cumplir las tres propiedades. Esto ilustra muy bien la importancia de dichas propiedades. • La versi´n final correcta se denomina Algoritmo de Dekker o • Por simplicidad, veremos algoritmos para 2 procesos unicamente. ´ • Se asume que hay dos procesos, denominados Proceso 0 y Proceso 1, cada uno de ellos ejecuta un bucle infinito conteniendo: 1. Protocolo de entrada (PE). 2. Secci´n cr´ o ıtica (SC). 3. Protocolo de salida (PS). 4. Otras sentencias del proceso (RS). Versi´n 1. Pseudoc´digo. o o En esta versi´n se usa una variable l´gica compartida (p01sc) que valdr´ true solo si el proceso 0 o el o o a proceso 1 est´n en SC, y valdr´ false si ninguno lo est´: a a a § { variables compartidas y valores iniciales } var p01sc : boolean := false ; { indica si la SC esta ocupada } ¦ § ¤ § process P0 ; process P1 ; begin begin while true do begin while true do begin while p01sc do begin end while p01sc do begin end p01sc := true ; p01sc := true ; { seccion critica } { seccion critica } p01sc := false ; p01sc := false ; { resto seccion } { resto seccion } end end end end ¦ ¥ ¦ ¤ ¥ ¤ ¥ creado October 4, 2013- p´gina 47 / 222 a
  • 48. SCD (13-14). Tema 2. Sincronizaci´n en memoria compartida.. o Versi´n 1. Correcci´n. o o Sin embargo, esa versi´n no es correcta. El motivo es que no cumple la propiedad de exclusi´n mutua, o o pues ambos procesos pueden estar en la secci´n cr´ o ıtica. Esto puede ocurrir si ambos leen p01sc y ambos la ven a false. es decir, si ocurre la siguiente secuencia de eventos: 1. el proceso 0 accede al protocolo de entrada, ve p01sc con valor false, 2. el proceso 1 accede al protocolo de entrada, ve p01sc con valor false, 3. el proceso 0 pone p01sc a true y entra en la secci´n cr´ o ıtica, 4. el proceso 1 pone p01sc a true y entra en la secci´n cr´ o ıtica. Versi´n 2. Pseudoc´digo. o o Para solucionar el problema se usar´ una unica variable l´gica (turno0), cuyo valor servir´ para indicar cual a ´ o a de los dos procesos tendr´ prioridad para entrar SC la pr´xima vez que llegen al PE. La variable valdr´ a o a true si la prioridad es para el proceso 0, y false si es para el proceso 1: § { variables compartidas y valores iniciales } var turno0 : boolean := true ; { podria ser tambien ’false’ } ¦ § ¤ § process P0 ; process P1 ; begin begin while true do begin while true do begin while not turno0 do begin end while turno0 do begin end { seccion critica } { seccion critica } turno0 := false ; turno0 := true ; { resto seccion } { resto seccion } end end end end ¦ ¥ ¦ ¤ ¥ ¤ ¥ Versi´n 2. Correcci´n. o o Esta segunda versi´n no es tampoco correcta, el motivo es distinto. Se dan estas circunstancias: o • Se cumple la propiedad de exclusi´n mutua. Esto es f´cil de verificar, ya que si un proceso est´ en o a a SC ha logrado pasar el bucle del protocolo de entrada y por tanto la variable turno0 tiene un valor que forzosamente hace esperar al otro. • No se cumple la propiedad de progreso en la ejecuci´n. El problema est´ en que este esquema obliga o a a los procesos a acceder de forma alterna a la secci´n cr´ o ıtica. En caso de que un proceso quiera acceder dos veces seguidas sin que el otro intente acceder m´s, la segunda vez quedar´ esperando a a indefinidamente. Este es un buen ejemplo de la necesidad de tener en cuenta cualquier secuencia posible de mezcla de pasos de procesamiento de los procesos a sincronizar. creado October 4, 2013- p´gina 48 / 222 a
  • 49. SCD (13-14). Tema 2. Sincronizaci´n en memoria compartida.. o Versi´n 3. Pseudoc´digo. o o Para solucionar el problema de la alternancia, ahora usamos dos variables l´gicas (p0sc, p1sc) en lugar de o solo una. Cada variable vale true si el correspondiente proceso est´ en la secci´n cr´ a o ıtica: § { variables compartidas y valores iniciales } var p0sc : boolean := false ; { verdadero solo si proc. 0 en SC } p1sc : boolean := false ; { verdadero solo si proc. 1 en SC } ¦ § ¤ § process P0 ; process P1 ; begin begin while true do begin while true do begin while p1sc do begin end while p0sc do begin end p0sc := true ; p1sc := true ; { seccion critica } { seccion critica } p0sc := false ; p1sc := false ; { resto seccion } { resto seccion } end end end end ¦ ¥ ¦ ¤ ¥ ¤ ¥ Versi´n 3. Correcci´n. o o De nuevo, esta versi´n no es correcta: o • Ahora s´ se cumple la propiedad de progreso en ejecuci´n, ya que los procesos no tienen que entrar ı o de forma necesariamente alterna, al usar dos variables independientes. Si un proceso quiere entrar, podr´ hacerlo si el otro no est´ en SC. a a • No se cumple, sin embargo, la exclusi´n mutua, por motivos parecidos a la primera versi´n, ya que se o o pueden producir secuencias de acciones como esta: ◾ el proceso 0 accede al protocolo de entrada, ve p1sc con valor falso, ◾ el proceso 1 accede al protocolo de entrada, ve p0sc con valor falso, ◾ el proceso 0 pone p0sc a verdadero y entra en la secci´n cr´ o ıtica, ◾ el proceso 1 pone p1sc a verdadero y entra en la secci´n cr´ o ıtica. Versi´n 4. Pseudoc´digo. o o Para solucionar el problema anterior se puede cambiar el orden de las dos sentencias del PE. Ahora las variables l´gicas p0sc y p1sc est´n a true cuando el correspondiente proceso est´ en SC, pero tambi´n o a a e cuando est´ intentando entrar (en el PE): a creado October 4, 2013- p´gina 49 / 222 a
  • 50. SCD (13-14). Tema 2. Sincronizaci´n en memoria compartida.. o § { variables compartidas y valores iniciales } var p0sc : boolean := falso ; { verdadero solo si proc. 0 en PE o SC } p1sc : boolean := falso ; { verdadero solo si proc. 1 en PE o SC } ¦ § ¤ § process P0 ; process P1 ; begin begin while true do begin while true do begin p0sc := true ; p1sc := true ; while p1sc do begin end while p0sc do begin end { seccion critica } { seccion critica } p0sc := false ; p1sc := false ; { resto seccion } { resto seccion } end end end end ¦ ¥ ¦ ¤ ¥ ¤ ¥ Versi´n 4. Correcci´n. o o De nuevo, esta versi´n no es correcta: o • Ahora s´ se cumple la exclusi´n mutua. Es f´cil ver que si un proceso est´ en SC, el otro no puede ı o a a estarlo. • Tambi´n se permite el entrelazamiento con regiones no cr´ e ıticas, ya que si un proceso accede al PE cuando el otro no est´ en el PE ni en el SC, el primero lograr´ entrar a la SC. a a • Sin embargo, no se cumple el progreso en la ejecuci´n, ya que puede ocurrir interbloqueo. En este o caso en concreto, eso puede ocurrir si se produce una secuencia de acciones como esta: ◾ el proceso 0 accede al protocolo de entrada, pone p0sc a verdadero, ◾ el proceso 1 accede al protocolo de entrada, pone p1sc a verdadero, ◾ el proceso 0 ve p1sc a verdadero, y entra en el bucle de espera, ◾ el proceso 1 ve p0sc a verdadero, y entra en el bucle de espera. Versi´n 5. Pseudoc´digo. o o Para solucionarlo, si un proceso ve que el otro quiere entrar, el primero pone su variable temporalmente a false: creado October 4, 2013- p´gina 50 / 222 a
  • 51. SCD (13-14). Tema 2. Sincronizaci´n en memoria compartida.. o 1 2 3 4 5 6 7 8 9 10 11 12 13 14 § var p0sc : boolean := false ; { true solo si proc. 0 en PE o SC } p1sc : boolean := false ; { true solo si proc. 1 en PE o SC } ¦ § ¤ § process P0 ; process P1 ; begin begin while true do begin while true do begin p0sc := true ; p1sc := true ; while p1sc do begin while p0sc do begin p0sc := false ; p1sc := false ; { espera durante un tiempo } { espera durante un tiempo } p0sc := true ; p1sc := true ; end end { seccion critica } { seccion critica } p0sc := false ; p1sc := false ; { resto seccion } { resto seccion } end end end end ¦ ¥ ¦ ¤ ¥ ¤ 1 2 3 4 5 6 7 8 9 10 11 12 13 14 ¥ Versi´n 5. Correcci´n. o o En este caso, se cumple exclusi´n mutua pero, sin embargo, no es posible afirmar que es imposible que se o produzca interbloqueo en el PE. Por tanto, no se cumple la propiedad de progreso. • La posibilidad de interbloqueo es peque˜a, y depende de c´mo se seleccionen las duraciones de los n o tiempos de la espera de cortes´ de c´mo se implemente dicha espera, y de la metodolog´ usada para ıa, o ıa asignar la CPU a los procesos o hebras a lo largo del tiempo. • En particular, y a modo de ejemplo, el interbloqueo podr´ ocurrir si ocurre que: ıa ◾ Ambos procesos comparten una CPU y la espera de cortes´ se implementa como una espera ıa ocupada. ◾ Los dos procesos acceden al bucle de las l´ ıneas 4-8 (ambas variables est´n a verdadero). a 3.2.2 ◾ Sistem´ticamente, cuando un proceso est´ en la CPU y ha terminado de ejecutar la asignaci´n a a o de la l´ ınea 7, la CPU se le asigna al otro. Algoritmo de Dekker Algoritmo de Dekker. Descripci´n. o El algoritmo de Dekker debe su nombre a su inventor, es un algoritmo correcto (es decir, cumple las propiedades m´ ınimas establecidas), y se puede interpretar como el resultado final del refinamiento sucesivo de Dijkstra: • Al igual que en la versi´n 5, cada proceso incorpora una espera de cortes´ durante la cual le cede al o ıa otro la posibilidad de entrar en SC, cuando ambos coinciden en el PE. • Para evitar interbloqueos, la espera de cortes´ solo la realiza uno de los dos procesos, de forma ıa alterna, mediante una variable de turno (parecido a la versi´n 2). o creado October 4, 2013- p´gina 51 / 222 a
  • 52. SCD (13-14). Tema 2. Sincronizaci´n en memoria compartida.. o • La variable de turno permite tambi´n saber cuando acabar la espera de cortes´ que se implementa e ıa, mediante un bucle (espera ocupada). Algoritmo de Dekker. Pseudoc´digo. o 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 § { variables compartidas y valores iniciales } var p0sc : boolean := falso ; { true solo si proc.0 en PE o SC } p1sc : boolean := falso ; { true solo si proc.1 en PE o SC } turno0 : boolean := true ; { true ==> pr.0 no hace espera de cortesia } ¦ § ¤ § process P0 ; process P1 ; begin begin while true do begin while true do begin p0sc := true ; p1sc := true ; while p1sc do begin while p0sc do begin if not turno0 then begin if turno0 then begin p0sc := false ; p1sc := false ; while not turno0 do while turno0 do begin end begin end p0sc := true ; p1sc := true ; end end end end { seccion critica } { seccion critica } turno0 := false ; turno0 := true ; p0sc := false ; p1sc := false ; { resto seccion } { resto seccion } end end end end ¦ ¥ ¦ 3.2.3 ¤ ¥ ¤ 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 ¥ Algoritmo de Peterson Algoritmo de Peterson. Descripci´n. o Este algoritmo (que tambi´n debe su nombre a su inventor), es otro algoritmo correcto para EM, que adem´s e a es m´s simple que el algoritmo de Dekker. a • Al igual que el algoritmo de Dekker, usa dos variables l´gicas que expresan la presencia de cada o proceso en el PE o la SC, m´s una variable de turno que permite romper el interbloqueo en caso de a acceso simult´neo al PE. a • La asignaci´n a la variable de turno se hace al inicio del PE en lugar de en el PS, con lo cual, en o caso de acceso simult´neo al PE, el segundo proceso en ejecutar la asignaci´n (at´mica) al turno da a o o preferencia al otro (el primero en llegar). • A diferencia del algoritmo de Dekker, el PE no usa dos bucles anidados, sino que unifica ambos en uno solo. Pseudoc´digo para 2 procesos. o El esquema del algoritmo queda como sigue: creado October 4, 2013- p´gina 52 / 222 a
  • 53. SCD (13-14). Tema 2. Sincronizaci´n en memoria compartida.. o 1 2 3 4 5 6 7 8 9 10 11 12 § { variables compartidas y valores iniciales } var p0sc : boolean := falso ; { true solo si proc.0 en PE o SC } p1sc : boolean := falso ; { true solo si proc.1 en PE o SC } turno0 : boolean := true ; { true ==> pr.0 no hace espera de cortesia } ¦ § ¤ § process P0 ; process P1 ; begin begin while true do begin while true do begin p0sc := true ; p1sc := true ; turno0 := false ; turno0 := true ; while p1sc and not turno0 do while p0sc and turno0 do begin end begin end { seccion critica } { seccion critica } p0sc := false ; p1sc := false ; { resto seccion } { resto seccion } end end end end ¦ ¥ ¦ ¤ ¥ ¤ 1 2 3 4 5 6 7 8 9 10 11 12 ¥ Demostraci´n de exclusi´n mutua. (1/2) o o Supongamos que en un instante de tiempo t ambos procesos est´n en SC, entonces: a (a) La ultima asignaci´n (at´mica) a la variable turno0 (l´ ´ o o ınea 5), previa a t, finaliz´ en un instante s (se o cumple s < t). (b) En el intervalo de tiempo (s, t], ninguna variable compartida ha podido cambiar de valor, ya que en ese intervalo ambos procesos est´n en espera ocupada o en la secci´n cr´ a o ıtica y no escriben esas variables. (c) Durante el intervalo (s, t], las variables p0sc y p1sc valen verdadero, ya que cada proceso puso la suya a verdadero antes de s, sin poder cambiarla durante (s, t]. Demostraci´n de exclusi´n mutua. (2/2) o o de las premisas anteriores de deduce que: (d) Si el proceso 0 ejecut´ el ultimo la l´ o ´ ınea 5 en el instante s, entonces no habr´ podido entrar en ıa SC entre s y t (la condici´n de espera del proc.0 se cumplir´ en el intervalo (s, t]), y por tanto en o ıa s forzosamente fue el proceso 1 el ultimo que asign´ valor a turno0, luego turno0 vale verdadero ´ o durante el intervalo (s, t]. (e) la condici´n anterior implica que el proceso 1 no estaba en SC en s, ni ha podido entrar a SC durante o (s, t] (ya que p0sc y turno0 vale verdadero), luego el proceso 1 no est´ en SC en t. a Vemos que se ha llegado a una contradicci´n con la hip´tesis de partida, que por tanto debe ser falsa, luego o o no puede existir ning´n instante en el cual los dos procesos est´n en SC, es decir, se cumple la exclusi´n u e o m´tua. u Espera limitada Supongamos que hay un proceso (p.ej. el 0) en espera ocupada en el PE, en un instante t, y veamos cuantas veces m puede entrar a SC el proceso 1 antes de que el 0 logre hacerlo: creado October 4, 2013- p´gina 53 / 222 a
  • 54. SCD (13-14). Tema 2. Sincronizaci´n en memoria compartida.. o • El proceso 0 puede pasar a la SC antes que el 1, en ese caso m = 0. • El proceso 1 puede pasar a la SC antes que el 0 (que contin´a en el bucle). En ese caso m = 1. u En cualquiera de los dos casos, el proceso 1 no puede despu´s llegar (o volver) a SC while el 0 contin´a en e u el bucle, ya que para eso el proceso 1 deber´ pasar antes por la asignaci´n de verdadero a turno0, y eso ıa o provocar´ que (despu´s de un tiempo finito) forzosamente el proceso 0 entra en SC while el 1 continua en ıa e su bucle. Por tanto, la cota que requiere la propiedad es n = 1. Progreso en la ejecuci´n o Para asegurar el progreso es necesario asegurar • Ausencia de interbloqueos en el PE: Esto es f´cil de demostrar pues si suponemos que hay interbloqueo a de los dos procesos, eso significa que son indefinida y simult´neamente verdaderas las dos condiciones a de los bucles de espera, y eso implica que es verdad turno0 y no turno0, lo cual es absurdo. • Independencia de procesos en RS: Si un proceso (p.ej. el 0) est´ en PE y el otro (el 1) est´ en a a RS, entonces p1sc vale falso y el proceso 0 puede progresar a la SC independientemente del comportamiento del proceso 1 (que podr´ terminar o bloquearse estando en RS, sin impedir por ello el ıa progreso del proc.0). El mismo razonamiento puede hacerse al rev´s. e Luego es evidente que el algoritmo cumple la condici´n de progreso. o 3.2.4 Algoritmo de Peterson para n procesos. Algoritmo de Peterson para n procesos. Peterson introdujo, junto con la versi´n vista, una generalizaci´n de su algoritmo para EM con n procesos. o o • Cada proceso i (con 0 ≤ i < n) puede estar en uno de n + 1 estados posibles, numerados de −1 a n − 1: ◾ El estado −1 indica que el proceso est´ en RS. a ◾ Los estados 0 al n − 2 indican que el proceso est´ en PE. a ◾ El estado n − 1 indica que el proceso est´ en SC. a • Al ingresar en PE, el proceso pasa al estado 0. Durante el PE cada proceso pasa por todos los estados 0 ≤ j < n en orden, y en cada estado j (con j < n − 1) hace espera ocupada antes de pasar al j + 1. • Las esperas est´n dise˜adas de forma que en cada estado j con j = 0, . . . , n − 1, puede haber n − j a n procesos como mucho. Esto asegura la EM pues en el estado n − 1 (es decir, en SC) solo habr´ un a proceso como mucho. Diagrama de estados. Las transiciones en rojo suponen espera ocupada. creado October 4, 2013- p´gina 54 / 222 a
  • 55. SCD (13-14). Tema 2. Sincronizaci´n en memoria compartida.. o Protocolo de entrada Max. n Max. n-1 Max. n-2 Max. 3 Max. 2 0 0 1 1 2 2 n-3 n-3 n-2 n-2 Max. 1 -1 -1 Resto Sección n-1 n-1 Sección Crítica Variables compartidas Las variables compartidas son dos vectores de enteros (de nombres estado y ultimo), que son escritos por cada proceso justo cuando accede a un nuevo estado: estado: la entrada i (con 0 ≤ i < n) contiene el estado del i-´simo proceso, es un valor entero entre −1 y e n − 1, ambos incluidos. Debe estar inicializado a −1. ultimo: la entrada j (con 0 ≤ j < n) contiene el ´ ındice del ultimo proceso en ingresar en el estado j (es un ´ valor entero entre 0 y n − 1). Su valor inicial es indiferente (ya que los procesos siempre escriben en una entrada antes de leerla). Condici´n de espera en cada estado o Inicialmente, todos los procesos ingresan al estado 0 al inicio del PE. El proceso i puede pasar del estado j al estado j + 1 tras hacer una espera ocupada, hasta que se d´ una cualquiera de estas dos condiciones: e (a) No hay otros procesos en el estado j ni en estados posteriores a j (incluyendo SC). En este caso el proceso i es el m´s avanzado de todos los procesos en PE o SC (decimos que i es el proceso l´ a ıder). Esto equivale a: ∀ k ∈ {0, . . . , n − 1} t.q. k ≠ i : estado[k] < estado[i] (b) Despu´s de que el proceso i ingresase al estado j, otros procesos tambi´n lo han hecho. Esto equivale e e a: i ≠ ultimo[j] creado October 4, 2013- p´gina 55 / 222 a
  • 56. SCD (13-14). Tema 2. Sincronizaci´n en memoria compartida.. o Pseudoc´digo. o § { Variables compartidas, valores iniciales y funciones } var estado : array [0..n − 1] of integer ; { estado de cada proc. (inic. −1) } ultimo : array [0..n − 2] of integer ; { ultimo proc. en cada estado del PE } function lider( i : integer) : boolean; { ⇐⇒ ∀ k ≠ i : estado[k] < estado[i] } ¤ { Procesos } process P[ mi_numero : 0 .. n − 1 ] ; begin while true do begin for mi_etapa := 0 to n − 2 do begin estado[mi_numero] := mi_etapa ; ultimo[mi_etapa] := mi_numero ; while ultimo[mi_etapa]==mi_numero and not lider(mi_numero) do begin end end estado[mi_numero] := n − 1 ; { seccion critica } estado[mi_numero] := −1 ; { resto seccion } end ¦ ¥ La funci´n l´gica lider. o o La funci´n lider lee la variable compartida estado, y devuelve verdadero solo si el i-´simo proceso es el m´s o e a avanzado de todos los que est´n en PE y SC: a § function lider( i : integer ) : boolean ; begin for k := 0 to n − 1 do if i ≠ k and estado[i] ≤ estado[k] then return false ; return true ; end ¦ 3.3 3.3.1 ¤ ¥ Soluciones hardware con espera ocupada (cerrojos) para E.M. Introducci´n o Introducci´n o Los cerrojos constituyen una soluci´n hardware basada en espera ocupada que puede usarse en procesos o concurrentes con memoria compartida para solucionar el problema de la exclusi´n mutua. o • La espera ocupada constituye un bucle que se ejecuta hasta que ning´n otro proceso est´ ejecutando u e instrucciones de la secci´n cr´ o ıtica • Existe un valor l´gico en una posici´n de memoria compartida (llamado cerrojo) que indica si alg´n o o u proceso est´ en la secci´n cr´ a o ıtica o no. creado October 4, 2013- p´gina 56 / 222 a
  • 57. SCD (13-14). Tema 2. Sincronizaci´n en memoria compartida.. o • En el protocolo de salida se actualiza el cerrojo de forma que se refleje que la SC ha quedado libre Veremos una soluci´n elemental que sin embargo es incorrecta e ilustra la necesidad de instrucciones o hardware espec´ ıficas (u otras soluciones m´s elaboradas). a Una posible soluci´n elemental o Vemos un esquema para procesos que ejecutan SC y RS repetidamente: § { variables compartidas y valores iniciales } var sc_ocupada : boolean := false ; { cerrojo: verdadero solo si SC ocupada } { procesos } process P[ i : 1 .. n ]; begin while true do begin while sc_ocupada do begin end sc_ocupada := true ; { seccion critica } sc_ocupada := false ; { resto seccion } end end ¦ ¤ ¥ Errores de la soluci´n simple o La soluci´n anterior no es correcta, ya que no garantiza exclusi´n mutua al existir secuencias de mezclado o o de instrucciones que permiten a m´s de un proceso ejecutar la SC a la vez: a • La situaci´n se da si n procesos acceden al protocolo de entrada y todos ellos leen el valor del cerrojo o a false (ninguno lo escribe antes de que otro lo lea). • Todos los procesos registran que la SC est´ libre, y todos acceden a ella. a • El problema es parecido al que ya vimos de acceso simult´neo a una variable en memoria compartida: a la lectura y posterior escritura del cerrojo se hace en varias sentencias distintas que se entremezclan. una soluci´n es usar instrucciones m´quina at´micas (indivisibles) para acceso a la zona de memoria donde o a o se aloja el cerrojo. Veremos dos de ellas: LeerAsignar (TestAndSet) e Intercambia (Swap). 3.3.2 La instrucci´n LeerAsignar. o La instrucci´n LeerAsignar. o Es una instrucci´n m´quina disponible en el repertorio de algunos procesadores. o a • admite como argumento la direcci´n de memoria de la variable l´gica que actua como cerrojo. o o • se invoca como una funci´n desde LLPP de alto nivel, y ejecuta estas acciones: o 1. lee el valor anterior del cerrojo creado October 4, 2013- p´gina 57 / 222 a
  • 58. SCD (13-14). Tema 2. Sincronizaci´n en memoria compartida.. o 2. pone el cerrojo a verdadero 3. devuelve el valor anterior del cerrojo • al ser una unica instrucci´n m´quina su ejecuci´n no puede entremezclarse con ninguna otra instrucci´n ´ o a o o ejecutada en el mismo procesador • bloquea el bus del sistema y la memoria donde est´ el cerrojo de forma que ninguna otra instrucci´n a o similar de otro procesador puede entremezclarse con ella. Protocolos de entrada y salida con LeerAsignar La forma adecuada de usar LeerAsignar es la que se indica en este esquema: § { variables compartidas y valores iniciales } var sc_ocupada : boolean := false ; { true solo si la SC esta ocupada } { procesos } process P[ i : 1 .. n ]; begin while true do begin while LeerAsignar( sc_ocupada ) do begin end { seccion critica } sc_ocupada := false ; { resto seccion } end end ¦ ¤ ¥ cuando hay m´s de un proceso intentando entrar en SC (estando SC libre), solo uno de ellos (el primero en a ejecutar LeerAsignar) ve el cerrojo (sc ocupada) a falso, lo pone a verdadero y logra entrar a SC. 3.3.3 La instrucci´n Intercambia. o La instrucci´n Intercambia. o Constituye otra instrucci´n hardware que, al igual que LeerAsignar, se ejecuta de forma at´mica en entornos o o con varios procesos ejecut´ndose en uno o varios procesadores compartiendo memoria. a • actua sobre un cerrojo (un valor l´gico) en memoria compartida o • admite dos argumentos: ◾ la direcci´n de memoria del cerrojo (variable global en memoria compartida) o ◾ la direcci´n de memoria de otra variable l´gica (no necesariamente compartida, t´ o o ıpicamente es una variable local del proceso que llama a Intercambia) o o • el efecto de la instrucci´n es intercambiar los dos valores l´gicos almacenados en las posiciones de memoria indicadas • se invoca como un procedimiento creado October 4, 2013- p´gina 58 / 222 a
  • 59. SCD (13-14). Tema 2. Sincronizaci´n en memoria compartida.. o Protocolos de entrada y salida con Intercambia La forma de usar Intercambia es como se indica aqu´ ı: § { variables compartidas y valores iniciales } var sc_libre : boolean := true ; { verdadero solo si la SC esta libre } { procesos } process P[ i : 1 .. n ]; var { variable no compartida: true solo si este proceso ocupa la SC } sc_ocupada_proc : boolean := falso ; begin while true do begin repeat Intercambia( sc_libre, sc_ocupada_proc ) ; until sc_ocupada_proc ; { seccion critica } intercambia( sc_libre, sc_ocupada_proc ) ; { resto seccion } end end ¦ ¤ ¥ Validez de Intercambia para exclusi´n mutua o Se puede verificar que funciona: • si hay n procesos conteniendo una secci´n cr´ o ıtica, habr´ n + 1 variables l´gicas involucradas: a o ◾ n variables locales (sc ocupada proc), una por proceso ◾ el cerrojo (sc libre) • en cada instante de tiempo, exactamente una de esas n + 1 variables l´gicas vale verdadero, y el resto o valen falso • este invariante se cumple debido a que: ◾ es inicialmente cierto (ver los valores iniciales) ◾ las llamadas a Intercambia no lo hacen falso por tanto se cumple la exclusi´n mutua ya que en cada instante solo el proceso cuya variable local este a o verdadero (si es que hay alguno) est´ en SC. a 3.3.4 Desventajas de los cerrojos. Desventajas de los cerrojos. Los cerrojos constituyen una solucion v´lida para EM que consume poca memoria y es eficiente en tiempo a (excluyendo las esperas ocupadas), sin embargo: • las esperas ocupadas consumen tiempo de CPU que podr´ dedicarse a otros procesos para hacer ıa trabajo util ´ creado October 4, 2013- p´gina 59 / 222 a
  • 60. SCD (13-14). Tema 2. Sincronizaci´n en memoria compartida.. o • se puede acceder directamente a los cerrojos y por tanto un programa err´neo o escrito malinteno cionadamente puede poner un cerrojo en un estado incorrecto, pudiendo dejar a otros procesos indefinidamente en espera ocupada. • en la forma b´sica que hemos visto no se cumplen ciertas condiciones de equidad a 3.3.5 Uso de los cerrojos. Uso de los cerrojos. Las desventajas indicadas hacen que el uso de cerrojos sea restringido, en el sentido que: • por seguridad, normalmente solo se usan desde componentes software que forman parte del sistema operativo, librer´ de hebras, de tiempo real o similares (estas componentes suelen estar bien comıas probadas y por tanto libres de errores o c´digo malicioso). o • para evitar la p´rdida de eficiencia que supone la espera ocupada, se usan solo en casos en los que e la ejecuci´n de la SC conlleva un intervalo de tiempo muy corto (por tanto las esperas ocupadas son o muy cortas, y la CPU no se desaprovecha). 3.4 3.4.1 Sem´foros para sincronizaci´n a o Introducci´n o Sem´foros. Introducci´n a o Los sem´foros constituyen un mecanismo que soluciona o aminora los problemas indicados para los cerrojos, a y tienen un ambito de uso m´s amplio: ´ a • no se usa espera ocupada, sino bloqueo de procesos (uso mucho m´s eficiente de la CPU) a • resuelven f´cilmente el problema de exclusi´n mutua con esquemas de uso sencillos a o • se pueden usar para resolver problemas de sincronizaci´n (aunque en ocasiones los esquemas de uso o son complejos) • el mecanismo se implementa mediante instancias de una estructura de datos a las que se accede unicamente mediante subprogramas espec´ ´ ıficos. Esto aumenta la seguridad y simplicidad. Bloqueo y desbloqueo de procesos Los sem´foros exigen que los procesos que deseen acceder a una SC no ocupen la CPU mientras esperan a a que otro proceso o hebra abandone dicha SC, esto implica que: • un proceso en ejecuci´n debe poder solicitar quedarse bloqueado o • un proceso bloqueado no puede ejecutar instrucciones en la CPU • un proceso en ejecuci´n debe poder solicitar que se desbloquee (se reanude) alg´n otro proceso o u bloqueado. creado October 4, 2013- p´gina 60 / 222 a
  • 61. SCD (13-14). Tema 2. Sincronizaci´n en memoria compartida.. o • deben poder existir simult´neamente varios conjuntos de procesos bloqueados. a • cada petici´n de bloqueo o desbloqueo se debe referir a alguno de estos conjuntos. o Todo esto requiere el uso de servicios externos (proporcionados por el sistema operativo o por la librer´ de ıa hebras), mediante una interfaz bien definida. 3.4.2 Estructura de un sem´foro a Estructura de un sem´foro a Un sem´foro es un instancia de una estructura de datos (un registro) que contiene los siguientes elementos: a • Un conjunto de procesos bloqueados (de estos procesos decimos que est´n esperando al sem´foro). a a • Un valor natural (un valor entero no negativo), al que llamaremos por simplicidad valor del sem´foro a Estas estructuras de datos residen en memoria compartida. Al inicio de un programa que los usa debe poder inicializarse cada sem´foro: a • el conjunto de procesos asociados estar´ vac´ a ıo • se deber´ indicar un valor inicial del sem´foro a a 3.4.3 Operaciones sobre los sem´foros. a Operaciones sobre los sem´foros a Adem´s de la inicializaci´n, solo hay dos operaciones b´sicas que se pueden realizar sobre una variable u a o a objeto cualquiera de tipo sem´foro (que llamamos s) : a • sem wait(s) ◾ Si el valor de s es mayor que cero, decrementar en una unidad dicho valor ◾ Si el valor de s es cero, bloquear el proceso que invoca en el conjunto de procesos bloqueados asociado a s • sem signal(s) ◾ Si el conjunto de procesos bloqueados asociado a s no est´ vac´ desbloquear uno de dichos a ıo, procesos. ◾ Si el conjunto de procesos bloqueados asociado a s est´ vac´ incrementar en una unidad el valor a ıo, de s. Invariante de un sem´foro a Dado un sem´foro s, en un instante de tiempo cualquiera t (en el cual el valor de s no est´ en proceso de a e actualizaci´n) se cumplir´ que: o a v0 + n s = v t + n w todos estos s´ ımbolos desginan n´meros enteros no negativos, en concreto: u creado October 4, 2013- p´gina 61 / 222 a
  • 62. SCD (13-14). Tema 2. Sincronizaci´n en memoria compartida.. o v0 = valor inicial de s vt = valor de s en el instante t. ns = n´mero total de llamadas a sem signal(s) completadas hasta el instante t. u nw = n´mero total de llamadas a sem wait(s) completadas hasta el instante t (no se incluyen los sem wait no u completados por haber dejado el proceso en espera). Implementaci´n de sem wait y sem signal. o Se pueden implementar con este esquema: § procedure sem_wait(var s:semaphore); begin if s.valor > 0 then s.valor := s.valor - 1 ; else bloquear( s.procesos ) ; end ¦ ¤ § procedure sem_signal(var s:semaphore); begin if vacio( s.procesos ) then s.valor := s.valor + 1 ; else desbloquear( s.procesos ) ; end ¥ ¦ ¤ ¥ En un sem´foro cualquiera, estas operaciones se ejecutan de forma at´mica, es decir, no puede haber dos a o procesos distintos ejecutando estas operaciones a la vez sobre un mismo sem´foro (excluyendo el per´ a ıodo de bloqueo que potencialmente conlleva la llamada a sem wait). 3.4.4 Uso de los sem´foros a Uso de sem´foros para exclusi´n mutua a o Los sem´foros se pueden usar para EM usando un sem´foro inicializado a 1, y haciendo sem wait en el a a protocolo de entrada y sem signal en el protocolo de salida: § { variables compartidas y valores iniciales } var sc_libre : semaphore := 1 ; { vale 1 si SC esta libre, 0 si SC esta ocupada } { procesos } process P[ i : 0..n ]; begin while true do begin sem_wait( sc_libre ) ; { esperar bloqueado hasta que sc libre sea 1 } { seccion critica: ...... } sem_signal( sc_libre ) ; { desbloquear proc. en espera o poner sc libre a 1 } { resto seccion: ....... } end end ¦ En cualquier instante de tiempo, la suma del valor del sem´foro m´s el n´mero de procesos en la SC es la a a u unidad. Por tanto, solo puede haber 0 o 1 procesos en SC, y se cumple la exclusi´n mutua. o creado October 4, 2013- p´gina 62 / 222 a ¤ ¥
  • 63. SCD (13-14). Tema 2. Sincronizaci´n en memoria compartida.. o Uso de sem´foros para sincronizaci´n a o El problema del Productor-Consumidor que vimos se puede resolver f´cilmente con sem´foros: a a § { variables compartidas y valores iniciales } var x : integer ; { producidos : integer :=0 ; { consumidos : integer :=0 ; { puede_leer : semaphore := 0 ; { puede_escribir : semaphore := 1 ; { ¦ § process Productor ; { calcula ’x’ } var a : integer ; begin while true do begin a := ProducirValor() ; sem_wait( puede_escribir ); x := a ; { sentencia E } producidos := producidos+1 ; sem_signal( puede_leer ) ; end end ¦ contiene cada valor producido } numero de valores producidos } numero de valores consumidos } 1 si se puede leer ’x’, 0 en otro caso } 1 si se puede escribir ’x’, 0 en otro caso } ¤ § process Consumidor { lee ’x’ } var b : integer ; begin while true do begin sem_wait( puede_leer ) ; b := x ; { sentencia L } consumidos := consumidos+1 ; sem_signal( puede_escribir ) ; UsarValor(b) ; end end ¥ ¦ Limitaciones de los sem´foros a Los sem´foros resuelven de una forma eficiente y sencilla el problema de la exclusi´n mutua y problemas a o sencillos de sincronizaci´n, sin embargo: o • los problemas m´s complejos de sincronizaci´n se resuelven de forma algo m´s compleja (es dif´ a o a ıcil verificar su validez, y es f´cil que sean incorrectos). a • al igual que los cerrojos, programas err´neos o malintencionados pueden provocar que haya procesos o bloqueados indefinidamente o en estados incorrectos. En la siguiente secci´n se ver´ una soluci´n de m´s alto nivel sin estas limitaciones (monitores). o a o a 3.5 3.5.1 Monitores como mecanismo de alto nivel Fundamento te´rico de los monitores o Fundamento te´rico de los monitores o • Inconvenientes de usar mecanismos como los sem´foros: a ◾ Basados en variables globales: esto impide un dise˜o modular y reduce la escalabilidad (incorn porar m´s procesos al programa suele requerir la revisi´n del uso de las variables globales). a o ◾ El uso y funci´n de las variables no se hace expl´ o ıcito en el programa, lo cual dificulta razonar sobre la correcci´n de los programas. o creado October 4, 2013- p´gina 63 / 222 a ¤ ¥ ¤ ¥
  • 64. SCD (13-14). Tema 2. Sincronizaci´n en memoria compartida.. o ◾ Las operaciones se encuentran dispersas y no protegidas (posibilidad de errores). • Es necesario un mecanismo que permita el acceso estructurado y la encapsulaci´n, y que adem´s proo a porcione herramientas para garantizar la exclusi´n mutua e implementar condiciones de sincronizaci´n o o 3.5.2 Definici´n de monitor o Definici´n de monitor o • C.A.R. Hoare (1974) Monitor: mecanismo de alto nivel que permite: ◾ Definir objetos abstractos compartidos: ▸ Colecci´n de variables encapsuladas (datos) que representan un recurso compartido por varios o procesos. ▸ Conjunto de procedimientos para manipular el recurso: afectan a las variables encapsuladas. ◾ Garantizar el acceso exclusivo a las variables e implementar sincronizaci´n. o • El recurso compartido se percibe como un objeto al que se accede concurrentemente. • Acceso estructurado y Encapsulaci´n: o ◾ El usuario (proceso) solo puede acceder al recurso mediante un conjunto de operaciones. ◾ El usuario ignora la/s variable/s que representan al recurso y la implementaci´n de las operao ciones asociadas. Propiedades de un monitor Exclusi´n mutua en el acceso a los procedimientos o • La exclusi´n mutua en el acceso a los procedimientos del monitor est´ garantizada por definici´n. o a o • La implementaci´n del monitor garantiza que nunca dos procesos estar´n ejecutando simult´neamente o a a alg´n procedimiento del monitor (el mismo o distintos). u Ventajas sobre los sem´foros (soluci´n no estructurada) a o • Las variables est´n protegidas, evitando interferencias exteriores. a • Acceso estructurado: Un proceso cualquiera solo puede acceder a las variables del monitor usando los procedimientos exportados por el monitor. Toda la espera y se˜alizaci´n se programan dentro del n o monitor. Si el monitor es correcto, lo ser´ cada instancia usada por los procesos. a • Exclusi´n mutua garantizada: evita errores. o creado October 4, 2013- p´gina 64 / 222 a
  • 65. SCD (13-14). Tema 2. Sincronizaci´n en memoria compartida.. o Sintaxis de un monitor Estructura de una declaraci´n de un monitor, de nombre nombre-monitor, con N procedimientos (con nombres: o nom proc 1,nom proc 2,. . .,nom proc n), de los cuales algunos son exportados (nom exp 1,nom exp 2,....): § monitor nombre monitor ; var ...... ; export nom exp 1,nom exp 2 .... ; ¤ { declaracion de variables permanentes (privadas) } { (se conservan entre llamadas al monitor) } { declaracion de procedimientos publicos } { (se indican solo los nombres) } procedure nom proc 1( ... ); { decl. de procedimiento y sus parametros formales } var ... ; { declaracion de variables locales a nom proc 1 } begin ... { codigo que implementa nom proc 1 } end ... { resto de procedimientos del monitor } begin .... end ¦ { codigo de inicializacion de vars. permanentes } Componentes de un monitor 1. Un conjunto de variables permanentes: • Almacenan el estado interno del recurso compartido que est´ siendo representado por el monitor. a • S´lo pueden ser accedidas dentro del monitor (en el cuerpo de los procedimientos y c´digo de o o inicializaci´n). o • Permanecen sin modificaciones entre dos llamadas consecutivas a procedimientos del monitor. 2. Un conjunto de procedimientos internos: • Manipulan las variables permanentes. • Pueden tener variables y par´metros locales, que toman un nuevo valor en cada activaci´n del a o procedimiento. • Algunos (o todos) constituyen la interfaz externa del monitor y podr´n ser llamados por los a procesos que comparten el recurso. 3. Un c´digo de inicializaci´n: o o • Inicializa las variables permanentes del monitor. • Se ejecuta una unica vez, antes de cualquier llamada a procedimiento del monitor. ´ creado October 4, 2013- p´gina 65 / 222 a ¥
  • 66. SCD (13-14). Tema 2. Sincronizaci´n en memoria compartida.. o Diagrama de las componentes del monitor El monitor se puede visualizar como aparece en el diagrama: • El uso que se hace del monitor se hace exclusivamente usando los procedimientos exportados (constituyen el interfaz con el exterior). • Las variables permanentes y los procedimientos no exportados no son accesibles desde fuera. • Ventaja: la implementaci´n de las operaciones se o puede cambiar sin modificar su sem´ntica. a Ejemplo de monitor (pseudoc´digo) o Monitor M Variables permanentes Procedimientos exportados C´digo de o inicializaci´n o OP1 OP2 ··· OPn Tenemos varios procesos que pueden incrementar (en una unidad) una variable compartida y poder examinar su valor en cualquier momento: § { declaracion del monitor } monitor VariableCompartida ; var x : integer; { permanente } export incremento, valor; ¤ § { ejemplo de uso del monitor } { (debe aparecer en el ambito de la } { declaracion del monitor) } VariableCompartida.incremento(); VariableCompartida.valor( k ) ; ¦ ¤ ¥ procedure incremento( ); begin x := x+1 ; { incrementa valor actual } end; procedure valor(var v:integer); begin v := x ; { copia sobre v valor actual } end; begin x := 0 ; { inicializa valor } end ¦ ¥ creado October 4, 2013- p´gina 66 / 222 a
  • 67. SCD (13-14). Tema 2. Sincronizaci´n en memoria compartida.. o 3.5.3 Funcionamiento de los monitores Funcionamiento de los monitores • Comunicaci´n monitor-mundo exterior: Cuando un proceso necesita operar sobre un recurso comparo tido controlado por un monitor deber´ realizar una llamada a uno de los procedimientos exportados a por el monitor usando los par´metros reales apropiados. a ◾ Cuando un proceso est´ ejecutando un procedimiento exportado del monitor decimos que est´ a a dentro del monitor. • Exclusi´n mutua: Si un proceso est´ ejecutando un procedimiento del monitor (est´ dentro del mismo), o a a ning´n otro proceso podr´ entrar al monitor (a cualquier procedimiento del mismo) hasta que el proceso u a que est´ dentro del monitor termine la ejecuci´n del procedimiento que ha invocado. a o ◾ Esta pol´ ıtica de acceso asegura que las variables permanentes nunca son accedidas concurrentemente. ◾ El acceso exclusivo entre los procedimientos del monitor debe estar garantizado en la implementaci´n de los monitores o Funcionamiento de los monitores (2) • Los monitores son objetos pasivos: Despu´s de ejecutar el c´digo de inicializaci´n, un monitor es un objeto pasivo y el c´digo de sus e o o o procedimientos s´lo se ejecuta cuando estos son invocados por los procesos. o • Instanciaci´n de monitores: Para cada recurso compartido se tendr´ que definir un monitor. Para o ıa recursos con estructura y comportamiento id´nticos podemos instanciar (de forma parametrizada) el e monitor tantas veces como recursos se quieran controlar. ◾ Declaraci´n de un tipo monitor e instanciaci´n: o o § class monitor nombre clase monitor( parametros formales ) ; .... .......... { cuerpo del monitor semejante a los anteriores } end var nombre instancia : nombre clase monitor( parametros actuales ) ; ¦ ◾ Implementaciones reentrantes: poder crear una nueva instancia independiente de un monitor para una tarea determinada permite escribir c´digo reentrante que realiza dicha tarea. o Ejemplo de instanciaci´n de un monitor o Podemos escribir un ejemplo similar a VariableCompartida, pero ahora parametrizado: creado October 4, 2013- p´gina 67 / 222 a ¤ ¥
  • 68. SCD (13-14). Tema 2. Sincronizaci´n en memoria compartida.. o § { declaracion del monitor } class monitor VarComp(pini,pinc : integer); var x, inc : integer; export incremento, valor; procedure incremento( ); begin x := x+inc ; end; procedure valor(var v : integer); begin v := x ; end; begin x:= pini ; inc := pinc ; end ¦ ¤ § { ejemplo de uso } var mv1 : VarComp(0,1); mv2 : VarComp(10,4); i1,i2 : integer ; begin mv1.incremento() ; mv1.valor(i1) ; { i1==1 } mv2.incremento() ; mv2.valor(i2) ; { i2==14 } end ¦ ¤ ¥ ¥ Cola del monitor para exclusi´n mutua o El control de la exclusi´n mutua se basa en la existencia de la cola del monitor: o • Si un proceso est´ dentro del monitor y otro proceso intenta ejecutar un procedimiento del monitor, a ´ste ultimo proceso queda bloqueado y se inserta en la cola del monitor e ´ • Cuando un proceso abandona el monitor (finaliza la ejecuci´n del procedimiento), se desbloquea un o proceso de la cola, que ya puede entrar al monitor • Si la cola del monitor est´ vac´ el monitor est´ libre y el primer proceso que ejecute una llamada a a ıa, a uno de sus procedimientos, entrar´ en el monitor a • Para garantizar la vivacidad del sistema, la planificaci´n de la cola del monitor debe seguir una pol´ o ıtica FIFO Cola del monitor Esta cola forma parte del estado del monitor: creado October 4, 2013- p´gina 68 / 222 a
  • 69. SCD (13-14). Tema 2. Sincronizaci´n en memoria compartida.. o Monitor M Cola del Monitor Variables permanentes Procedimientos exportados 3.5.4 C´digo de o inicializaci´n o Proceso7 OP1 ··· M.OP2 () ··· M.OP1 () ··· Proceso4 · · · ··· M.OP4 () ··· M.OP1 () ··· Proceson ··· M.OPi () ··· M.OPj () ··· null OP2 ··· OPn Sincronizaci´n en monitores o Sincronizaci´n en monitores o • Para implementar la sincronizaci´n, se requiere de una facilidad para bloqueo-activaci´n de acuerdo o o a una condici´n. o • En sem´foros, las instrucciones de sincronizaci´n presentan: a o ◾ Bloqueo-activaci´n o ◾ Cuenta, para representar la condici´n. o • En monitores: ◾ S´lo se dispone de sentencias Bloqueo-activaci´n. o o ◾ La condici´n se representa mediante los valores de las variables permanentes del monitor. o Primitivas de bloqueo-activaci´n en monitores o ◾ wait: Estoy esperando a que alguna condici´n ocurra. o Bloquea al proceso llamador. ◾ signal: Estoy se˜alando que una condici´n ocurre. n o Reactiva a un proceso esperando a dicha condici´n (si no hay ninguno no hace nada). o creado October 4, 2013- p´gina 69 / 222 a
  • 70. SCD (13-14). Tema 2. Sincronizaci´n en memoria compartida.. o Ejemplo de monitor para planificar un ´nico recurso u Este monitor permite gestionar el acceso a un recurso que debe usarse en E.M. por parte de varios procesos: § monitor recurso; ocupado : boolean; noocupado : condition; export adquirir, liberar ; ¤ var ¦ § procedure adquirir; begin if ocupado then noocupado.wait(); ocupado := true; end; ¦ § { inicializacion } begin ocupado := false; end ¦ ¤ § procedure liberar; begin ocupado:=false; noocupado.signal(); end; ¥ ¦ ¥ ¤ ¥ ¤ ¥ Variables condici´n o se˜ales (1) o n Para gestionar las condiciones de sincronizaci´n en monitores se utilizan las se˜ales o variables de o n condici´n: o • Debe declararse una variable condici´n para cualquier condici´n l´gica de sincronizaci´n que se pueda o o o o dar entre los procesos del programa (por cada raz´n de bloqueo basada en los valores de las variables o permanentes del monitor). • No tienen valor asociado (no requieren inicializaci´n). o • Representan colas (inicialmente vac´ de procesos esperando la condici´n. ıas) o • M´s de un proceso podr´ estar dentro del monitor, aunque solo uno estar´ ejecut´ndose (el resto a a a a estar´n bloqueados en variables condici´n). a o Colas de condici´n o se˜ales (2) o n • Dada una variable condici´n cond, se definen al menos las siguientes operaciones asociadas a cond: o Operaciones sobre variables condici´n o ◾ cond.wait(): Bloquea al proceso que la llama y lo introduce en la cola de la variable condici´n. o ◾ cond.signal(): Si hay procesos bloqueados por esa condici´n, libera uno de ellos. o ◾ cond.queue(): Funci´n booleana que devuelve verdadero si hay alg´n proceso esperando en o u la cola de cond y falso en caso contrario. • Cuando hay m´s de un proceso esperando en una condici´n cond: a o creado October 4, 2013- p´gina 70 / 222 a
  • 71. SCD (13-14). Tema 2. Sincronizaci´n en memoria compartida.. o ◾ Propiedad FIFO: cond.signal() reactivar´ al proceso que lleve m´s tiempo esperando. a a ◾ Evita la inanici´n: Cada proceso en cola obtendr´ eventualmente su turno. o a Variables condici´n y colas asociadas. o Los procesos 2 y 5 ejecutan las operaciones 1 y 2, ambas producen esperas de la condici´n B. o Monitor M Cola del Monitor Proceso7 Variables permanentes Variables condici´n o Cond.A null Cond.B ··· Procedimientos exportados C´digo de o inicializaci´n o Proceso4 · · · OP1 OP2 ··· B.wait ··· ··· OPn Proceso2 ··· B.wait ··· B.wait ··· M.OP1 () ··· Proceson null Proceso5 ··· M.OP2 () ··· null Colas de condici´n con prioridad o • Por defecto, se usan colas de espera FIFO. • A veces resulta util disponer de un mayor control sobre la estrategia de planificaci´n, dando la prioridad ´ o del proceso en espera como un nuevo par´metro: a cond.wait (prioridad:integer) ◾ Tras bloqueo, ordena los procesos en cola en base al valor de prioridad ◾ cond.signal() reanuda proceso que especific´ el valor m´s bajo de prioridad. o a • Precauci´n al dise˜ar el monitor: Evitar riesgos como la inanici´n. o n o • Ning´n efecto sobre la l´gica del programa: Funcionamiento similar con/sin colas de prioridad. u o • S´lo mejoran las caracter´ o ısticas dependientes del tiempo. creado October 4, 2013- p´gina 71 / 222 a
  • 72. SCD (13-14). Tema 2. Sincronizaci´n en memoria compartida.. o Ejemplo de cola con prioridad(1): Asignador Asigna un recurso al siguiente trabajo m´s corto: a § monitor asignador; libre : boolean ; turno : condition ; export peticion, liberar ; ¤ var ¦ § procedure peticion(tiempo: integer); begin if not libre then turno.wait( tiempo ); libre := false ; end ¦ § { inicializacion } begin libre := true ; end ¦ ¤ § procedure liberar() ; begin libre := true ; turno.signal(); end ¦ ¥ ¥ ¤ ¥ Ejemplo de cola con prioridad (2): Reloj con alarma El proceso llamador se retarda n unidades de tiempo: § monitor despertador; ahora : integer ; despertar : condition ; export despiertame, tick ; ¥ ¤ ¤ var ¦ § procedure despiertame( n: integer ); var alarma : integer; begin alarma := ahora + n; while ahora<alarma do despertar.wait( alarma ); despertar.signal(); { por si otro proceso coincide en la alarma } end ¦ § { Inicializacion } begin ahora := 0 ; end ¦ El problema de los lectores-escritores (LE) ¤ § procedure tick(); begin ahora := ahora+1 ; despertar.signal(); end ¦ ¥ ¤ ¥ ¤ ¥ ¥ creado October 4, 2013- p´gina 72 / 222 a
  • 73. SCD (13-14). Tema 2. Sincronizaci´n en memoria compartida.. o En este ejemplo, hay dos tipos de procesos que acceden concurrentemente a una estructura de datos en memoria compartida: escritores son procesos que modifican la estructura de datos (escriben en ella). El c´digo de escritura no o puede ejecutarse concurrentemente con ninguna otra escritura ni lectura, ya que est´ formado por una a secuencia de instrucciones que temporalmente ponen la estructura de datos en un estado no usable por otros procesos. lectores son procesos que leen a estructura de datos, pero no modifican su estado en absoluto. El c´digo o de lectura puede (y debe) ejecutarse concurrentemente por varios lectores de forma arbitraria, pero no puede hacerse a la vez que la escritura. la soluci´n de este problema usando sem´foros es compleja, veremos que con monitores es sencillo. o a LE: vars. permanentes y procedimientos para lectores § monitor Lec_Esc ; var n_lec escribiendo lectura escritura : : : : integer boolean condition condition ; ; ; ; { { { { ¤ numero de lectores leyendo } true si hay algun escritor escribiendo } no hay escritores escribiendo, lectura posible } no hay lectores ni escritores, escritura posible } export inicio_lectura, fin_lectura, inicio_escritura, fin_escritura ; ¦ § ¤ § procedure inicio_lectura() procedure fin_lectura() begin begin if escribiendo then { si hay escritor } n_lec:= n_lec - 1; lectura.wait() ; { se bloquea } if n_lec = 0 then n_lec := n_lec + 1 ; { si es el ultimo lector , } { desbloqueo en cadena de posibles } { desbloquear a un escritor } { procesos lectores bloqueados } escritura.signal() lectura.signal() end ¦ end ¦ ¥ ¥ ¤ ¥ LE: procedimientos para escritores creado October 4, 2013- p´gina 73 / 222 a
  • 74. SCD (13-14). Tema 2. Sincronizaci´n en memoria compartida.. o § procedure inicio_escritura() begin {si hay procs. accediendo: esperar} if n_lec > 0 or escribiendo then escritura.wait() escribiendo:= true; end; ¦ § begin { inicializacion } n_lec := 0 ; escribiendo := false ; end ¦ ¤ § procedure fin_escritura() begin escribiendo:= false; if lectura.queue() then {si hay lect.:} lectura.signal(); {despertar uno } else {si no hay lect:} escritura.signal() ; {desp. escr.} ¥ end; ¦ ¥ ¤ ¥ LE: uso del monitor Los procesos lectores y escritores tendr´ el siguiente aspecto: ıan § monitor Lec_Esc ; .... end ¦ § process Lector[ i:1..n ] ; begin while true do begin .......... Lec_Esc.inicio_lectura() ; { codigo de lectura } Lec_Esc.fin_lectura() ; .......... end end ¦ ¤ ¤ ¤ § process Escritor[ i:1..m ] ; begin while true do begin .......... Lec_Esc.inicio_escritura() ; { codigo de escritura } Lec_Esc.fin_escritura() ; .......... end end ¥ ¦ ¥ ¤ ¥ En esta implementaci´n se ha dado prioridad a los lectores (en el momento que un escritor termina, si hay o escritores y lectores esperando, pasan los lectores). 3.5.5 Sem´ntica de las se˜ales de los monitores a n Efectos de las operaciones sobre la E.M. • Es necesario liberar la E.M. del monitor justo antes de ejecutar una operaci´n cond.wait() para no o generar un interbloqueo en la cola de procesos del monitor. • Cuando se libera un proceso que est´ esperando por una condici´n cond (proceso se˜alado) es porque a o n otro proceso (proceso se˜alador) ha ejecutado una operaci´n cond.signal(): n o ◾ El proceso se˜alado tiene preferencia para acceder al monitor frente a los que esperan en la cola n del monitor (ya que ´stos podr´ cambiar el estado que ha permitido su liberaci´n). e ıan o creado October 4, 2013- p´gina 74 / 222 a
  • 75. SCD (13-14). Tema 2. Sincronizaci´n en memoria compartida.. o ◾ Si el proceso se˜alador continuase ”dentro” del monitor, tendr´ n ıamos una violaci´n de la E.M. del o monitor ◾ El comportamiento concreto del proceso se˜alador depender´ de la sem´ntica de se˜ales que se n a a n haya establecido en la implementaci´n del monitor. o • Algunos lenguajes implementan una operaci´n que permite liberar a todos los procesos esperando por o una condici´n (signal_all). o Se˜alar y continuar (SC) n • El proceso se˜alador contin´a su ejecuci´n dentro del monitor hasta que sale del mismo (porque n u o termina la ejecuci´n del procedimiento) o se bloquea en una condici´n. En ese momento, el proceso o o se˜alado se reactiva y contin´a ejecutando c´digo del monitor. n u o • Al continuar dentro del monitor, el proceso se˜alador podr´ cambiar el estado del monitor y hacer n ıa falsa la condici´n l´gica por la que esperaba el proceso se˜alado. o o n • Por tanto, en el proceso se˜alado no se puede garantizar que la condici´n asociada a cond es cierta n o al terminar cond.wait(), y l´gicamente es necesario volver a comprobarla entonces. o • Esta sem´ntica obliga a programar la operaci´n wait en un bucle, de la siguiente manera: a o § ¤ while not condicion l´gica desbloqueo do o cond.wait() ; ¦ ¥ Se˜alar y salir (SS) n • Si hay procesos bloqueados por la condici´n cond, el proceso se˜alador sale del monitor despu´s de o n e ejecutar cond.signal(). • En ese caso, la operaci´n signal conlleva: o ◾ Liberar al proceso se˜alado. n ◾ Terminaci´n del procedimiento del monitor que estaba ejecutando el proceso se˜alador. o n • Est´ asegurado el estado que permite al proceso se˜alado continuar la ejecuci´n del procedimiento a n o del monitor en el que se bloque´ (la condici´n de desbloqueo se cumple). o o • Esta sem´ntica condiciona el estilo de programaci´n ya que obliga a colocar siempre la operaci´n a o o signal como ´ltima instrucci´n de los procedimientos de monitor que la usen. u o Se˜alar y esperar (SE) n • El proceso se˜alador se bloquea justo despu´s de ejecutar la operaci´n signal. n e o • El proceso se˜alado entra de forma inmediata en el monitor. n creado October 4, 2013- p´gina 75 / 222 a
  • 76. SCD (13-14). Tema 2. Sincronizaci´n en memoria compartida.. o • Est´ asegurado el estado que permite al proceso se˜alado continuar la ejecuci´n del procedimiento a n o del monitor en el que se bloque´. o • El proceso se˜alador entra en la cola de procesos del monitor, por lo que est´ al mismo nivel que el n a resto de procesos que compiten por la exclusi´n mutua del monitor. o • Puede considerarse una sem´ntica ”injusta” respecto al proceso se˜alador ya que dicho proceso ya a n hab´ obtenido el acceso al monitor por lo que deber´ tener prioridad sobre el resto de procesos que ıa ıa compiten por el monitor. Se˜alar y espera urgente (SU) n • Esta soluci´n intenta corregir el problema de falta de equitatividad de la soluci´n anterior. o o • El proceso se˜alador se bloquea justo despu´s de ejecutar la operaci´n signal. n e o • El proceso se˜alado entra de forma inmediata en el monitor. n • Est´ asegurado el estado que permite al proceso se˜alado continuar la ejecuci´n del procedimiento a n o del monitor en el que se bloque´. o • El proceso se˜alador entra en una nueva cola de procesos que esperan para acceder al monitor, que n podemos llamar cola de procesos urgentes. • Los procesos de la cola de procesos urgentes tienen preferencia para acceder al monitor frente a los procesos que esperan en la cola del monitor. • Es la sem´ntica que se supone en los ejemplos vistos. a Procesos en la cola de urgentes. El proceso 1 y el 9 han ejecutado la op.2, que hace signal de la cond. B. creado October 4, 2013- p´gina 76 / 222 a
  • 77. SCD (13-14). Tema 2. Sincronizaci´n en memoria compartida.. o Monitor M Cola del Monitor Variables permanentes Variables condici´n o Cond.A null Cond.B ··· Procedimientos exportados C´digo de o inicializaci´n o Cola de urgentes (SU) Proceso4 · · · Proceso7 OP1 OP2 OP1 ··· B.wait() ··· OP2 ··· B.signal() ··· ··· OPn Proceso1 ··· M.OP2 () ··· Proceson Proceso2 ··· M.OP1 () ··· Proceso9 ··· M.OP2 () ··· Proceso5 ··· M.OP1 () ··· null null null An´lisis comparativo de las diferentes sem´nticas a a Potencia expresiva Todas las sem´nticas son capaces de resolver los mismos problemas. a Facilidad de uso La sem´ntica SS condiciona el estilo de programaci´n y puede llevar a aumentar de forma ”artificial” el a o n´mero de procedimientos. u Eficiencia • Las sem´nticas SE y SU resultan ineficientes cuando la operaci´n signal se ejecuta al final de los a o procedimientos del monitor. El proceso se˜alador se bloquea dentro del monitor cuando ya no le quedan m´s instrucciones que n a ejecutar en el procedimiento, suponiendo un bloqueo innecesario que conlleva un innecesario doble cambio de contexto en CPU (reactivaci´n se˜alado + salida). o n • La sem´ntica SC tambi´n es un poco ineficiente al obligar a usar un bucle while para cada instrucci´n a e o signal. creado October 4, 2013- p´gina 77 / 222 a
  • 78. SCD (13-14). Tema 2. Sincronizaci´n en memoria compartida.. o 3.5.6 Implementaci´n de monitores o Implementaci´n de monitores con sem´foros o a La exclusi´n mutua en el acceso a los procs. del monitor se puede implementar con un unico sem´foro mutex o ´ a inicializado a 1: § procedure P1(...) begin sem_wait(mutex); { cuerpo del procedimiento } sem_signal(mutex); end ¦ ¤ § { inicializacion } mutex := 1 ; ¦ ¤ ¥ ¥ Para implementar la sem´ntica SU necesitamos adem´s un sem´foro next, para implementar la cola de a a a urgentes, y una variable entera next_count para contar los procesos bloqueados en esa cola: § procedure P1(...) begin sem_wait(mutex); { cuerpo del procedimiento } if next_count > 0 then sem_signal(next); else sem_signal(mutex); end ¦ ¤ § { inicializacion } next := 0 ; next_count :=0 ; ¦ ¤ ¥ ¥ Implementaci´n de monitores con sem´foros o a Para implementar las variables condici´n le asociamos un sem´foro a cada una de ellas x_sem (inicializado o a a 0) y una variable para contar los procesos bloqueados en cada una de ellas (x_sem_count inicializada a 0): Implementaci´n de x.wait() o § x_sem_count := x_sem_count + 1 ; if next_count <> 0 then sem_signal(next) ; else sem_signal(mutex); sem_wait(x_sem); x_sem_count := x_sem_count - 1 ; ¦ Implementaci´n de x.signal() o ¤ § if x_sem_count <> 0 then begin next_count := next_count + 1 ; sem_signal(x_sem); sem_wait(next); next_count := next_count - 1 ; end ¦ ¥ Implementaci´n de monitores con sem´foros o a Cada monitor tiene asociadas las siguientes colas de procesos: • Cola del monitor: controlada por el sem´foro mutex. a • Cola de procesos urgentes: controlada por el sem´foro next y el n´mero de procesos en cola se a u contabiliza en la variable next_count. Esta cola solo es necesaria para implementar la sem´ntica a SU. creado October 4, 2013- p´gina 78 / 222 a ¤ ¥
  • 79. SCD (13-14). Tema 2. Sincronizaci´n en memoria compartida.. o • Colas de procesos bloqueados en cada condici´n: controladas por el sem´foro asociado a cada o a condici´n (x_sem) y el n´mero de procesos en cada cola se contabiliza en una variable asociada a o u cada condici´n (x_sem_count). o Esta implementaci´n no permite llamadas recursivas a los procedimientos del monitor y no asegura la o suposici´n FIFO sobre las colas de exclusi´n mutua y de las se˜ales. o o n Los sem´foros y monitores son equivalentes en potencia expresiva pero los monitores facilitan el desarrollo. a 3.5.7 Verificaci´n de monitores o Verificaci´n de programas con monitores o • La verificaci´n de la correcci´n de un programa concurrente con monitores requiere: o o ◾ Probar la correcci´n de cada monitor. o ◾ Probar la correcci´n de cada proceso de forma aislada. o ◾ Probar la correcci´n de la ejecuci´n concurrente de los procesos implicados. o o • El programador no puede conocer a priori el orden en que se ejecutar´n los procedimientos del monitor. a • El enfoque de verificaci´n que vamos a seguir utiliza un invariante de monitor: o ◾ Establece una relaci´n constante entre los valores permitidos de las variables del monitor. o ◾ Debe ser cierto cuando un procedimiento empieza a ejecutarse. ◾ Debe ser cierto cuando un procedimiento termine de ejecutarse. ◾ Debe ser cierto cuando un procedimiento llegue a una llamada a wait. Invariante del monitor (I M) • I M se ha de cumplir despu´s de la inicializaci´n de las variables permanentes. e o • I M se ha de cumplir antes y despu´s de cada acci´n. e o • I M se ha de cumplir antes y despu´s de cada operaci´n wait. Una vez el proceso ha sido liberado (por e o una operaci´n signal ejecutada por otro proceso), se debe cumplir la condici´n que permite liberarlo. o o • IM se ha de cumplir antes y despu´s de cada operaci´n signal sobre una condici´n. Tambi´n se debe e o o e cumplir antes la condici´n que permite liberar a un proceso. o Bibliograf´ del tema 2. ıa Para m´s informaci´n m´s detallada, ejercicios y bibliograf´ adicional, se puede consultar: a o a ıa 2.1. Introducci´n Palma (2003) cap´ o ıtulo 3. 2.2. Soluciones software con Espera Ocupada para E.M. Palma (2003) cap´ ıtulo 3, Ben Ari (2006) cap´ ıtulo 3 creado October 4, 2013- p´gina 79 / 222 a
  • 80. SCD (13-14). Tema 2. Sincronizaci´n en memoria compartida.. o 2.3. Soluciones hardware con Espera Ocupada para E.M. Palma (2003) cap´ ıtulo 3, Andrews (2000) cap´ ıtulo 3 2.4. Sem´foros para sincronizaci´n. Palma (2003) cap´ a o ıtulo 4, Andrews (2000) cap´ ıtulo 4, Ben Ari (2006) cap´ ıtulo 6 2.5. Monitores como mecanismo de alto nivel. Palma (2003) cap´ ıtulo 6, Andrews (2000) cap´ ıtulo 5, Ben Ari (2006) cap´ ıtulo 7 3.6 9 Problemas del tema 2. ¿Podr´ pensarse que una posible soluci´n al problema de la exclusi´n mutua, ser´ el siguiente algoritmo ıa o o ıa que no necesita compartir una variable Turno entre los 2 procesos? (a) ¿Se satisface la exclusi´n mutua? o (b) ¿Se satisface la ausencia de interbloqueo? 1 2 3 4 5 6 7 8 9 10 11 12 13 14 § { variables compartidas y valores iniciales } var c0, c1 : integer ; { los valores iniciales no son relevantes } ¦ § ¤ § Process P0 ; process P1 ; begin begin while true do begin while true do begin c0 := 0 ; c1 := 0 ; while c1 = 0 do begin while c0 = 0 do begin c0 := 1 ; c1 := 1 ; while c1 = 0 do begin end while c0 = 0 do begin end c0 := 0 ; c1 := 0 ; end end { seccion critica } { seccion critica } c0 := 1 ; c1 := 1 ; { resto sentencias } { resto seccion } end end end end ¦ ¥ ¦ ¤ ¥ ¤ 1 2 3 4 5 6 7 8 9 10 11 12 13 14 ¥ 10 Al siguiente algoritmo se le conoce como soluci´n de Hyman al problema de la exclusi´n mutua. ¿Es correcta o o dicha soluci´n? o creado October 4, 2013- p´gina 80 / 222 a
  • 81. SCD (13-14). Tema 2. Sincronizaci´n en memoria compartida.. o 1 2 3 4 5 6 7 8 9 10 11 12 13 § { variables compartidas y valores iniciales } var c0 : integer := 1 ; c1 : integer := 1 ; turno : integer := 1 ; ¦ § process P0 ; begin while true do begin c0 := 0 ; while turno != 0 do begin while c1 = 0 do begin end turno := 0 ; end { seccion critica } c0 := 1 ; { resto sentencias } end end ¦ ¤ ¥ ¤ ¤ § process P1 ; begin while true do begin c1 := 0 ; while turno != 1 do begin while c0 = 0 do begin end turno := 1 ; end { seccion critica } c1 := 1 ; { resto sentencias } end end ¥ ¦ 1 2 3 4 5 6 7 8 9 10 11 12 13 ¥ 11 Se tienen 2 procesos concurrentes que representan 2 m´quinas expendedoras de tickets (se˜alan el turno a n en que ha de ser atendido el cliente), los n´meros de los tickets se representan por dos variables n1 y n2 u que valen inicialmente 0. El proceso con el n´mero de ticket m´s bajo entra en su secci´n cr´ u a o ıtica. En caso de tener 2 n´meros iguales se procesa primero el proceso n´mero 1. u u a) Demostrar que se verifica la ausencia de bloqueo y la ausencia de inanci´n. o b) Demostrar que las asignaciones n1:=1 y n2:=1 son ambas necesarias. § { variables compartidas y valores iniciales } var n1 : integer := 0 ; n2 : integer := 0 ; ¦ § process P1 ; begin while true do begin n1 := 1 ; { n1 := n2+1 ; { while n2 != 0 and { n2 < n1 do begin end;{ { seccion critica } n1 := 0 ; { { resto sentencias } end end ¦ 1.0 1.1 1.2 1.3 } } } } 1.4 } ¤ § process P2 ; begin while true do begin n2 := 1 ; { 2.0 n2 := n1+1 ; { 2.1 while n1 != 0 and { 2.2 n1 <= n2 do begin end;{ 2.3 { seccion critica } n2 := 0 ; { 2.4 { resto sentencias } end end ¥ ¦ ¤ ¥ ¤ } } } } } ¥ creado October 4, 2013- p´gina 81 / 222 a
  • 82. SCD (13-14). Tema 2. Sincronizaci´n en memoria compartida.. o 12 El siguiente programa es una soluci´n al problema de la exclusi´n mutua para 2 procesos. Discutir la o o correcci´n de esta soluci´n: si es correcta, entonces probarlo. Si no fuese correcta, escribir escenarios que o o demuestren que la soluci´n es incorrecta. o 1 2 3 4 5 6 7 8 9 10 11 § { variables compartidas y valores iniciales } var c0 : integer := 1 ; c1 : integer := 1 ; ¦ § process P0 ; begin while true do begin repeat c0 := 1-c1 ; until c1 != 0 ; { seccion critica } c0 := 1 ; { resto sentencias } end end ¦ ¤ ¤ § process P1 ; begin while true do begin repeat c1 := 1-c0 ; until c0 != 0 ; { seccion critica } c1 := 1 ; { resto sentencias } end end ¥ ¦ ¥ ¤ 1 2 3 4 5 6 7 8 9 10 11 ¥ 13 Considerar el siguiente algoritmo de exclusi´n mutua para n procesos (algoritmo de Knuth). Escribir un o escenario en el que 2 procesos consiguen pasar el bucle de las l´ ıneas 14 a 16, suponiendo que el turno lo tiene inicialmente el proceso 0. creado October 4, 2013- p´gina 82 / 222 a
  • 83. SCD (13-14). Tema 2. Sincronizaci´n en memoria compartida.. o 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 § { variables compartidas y valores iniciales } var c : array[0..n-1] of (pasivo,solicitando,enSC) := [pasivo,..,pasivo]; turno: integer := 0 ; ¦ § process P[ i : 0..n-1 ] ; begin while true do begin repeat c[i] := solicitando ; j := turno; while j <> i do begin if c[j] <> pasivo then j := turno ; else j := (j-1) mod n ; end c[i] := enSC ; k := 0; while k<=n and ( k=i or c[k]<>enSC ) do k := k+1; until k > n ; turno := i ; { seccion critica } turno := (i-1) mod n ; c[i] := pasivo ; { resto sentencias } end end ¦ 14 ¤ ¥ ¤ ¥ Supongamos que tres procesos concurrentes acceden a dos variables compartidas (x e y) seg´n el siguiente u esquema: § var x, y : integer ; ¦ § { accede a ’ x ’ } process P1 ; begin while true do begin x := x+1 ; { .... } end end ¦ ¤ ¤ § { accede a ’ x ’ e ’ y’ } process P2 ; begin while true do begin x := x+1 ; y := x ; { .... } end ¥ end ¦ ¤ § { accede a ’ y’ } process P3 ; begin while true do begin y := y+1 ; { .... } end end ¦ ¥ ¥ ¤ ¥ con este programa como referencia, realiza estas dos actividades: 1. usando un unico sem´foro para exclusi´n mutua, completa el programa de forma que cada proceso ´ a o creado October 4, 2013- p´gina 83 / 222 a
  • 84. SCD (13-14). Tema 2. Sincronizaci´n en memoria compartida.. o realice todos sus accesos a x e y sin solaparse con los otros procesos (ten en cuenta que el proceso 2 debe escribir en y el mismo valor que acaba de escribir en x). 2. la asignaci´n x:=x+1 que realiza el proceso 2 puede solaparse sin problemas con la asignaci´n y:=y+1 o o que realiza el proceso 3, ya que son independientes. Sin embargo, en la soluci´n anterior, al usar un o unico sem´foro, esto no es posible. Escribe una nueva soluci´n que permita el solapamiento descrito, ´ a o usando dos sem´foros para dos secciones cr´ a ıticas distintas (las cuales, en el proceso 2, aparecen anidadas). 15 En algunas aplicaciones es necesario tener exclusi´n mutua entre procesos con la particularidad de que o puede haber como mucho n procesos en una secci´n cr´ o ıtica, con n arbitrario y fijo, pero no necesariamente igual a la unidad sino posiblemente mayor. Dise˜a una soluci´n para este problema basada en el uso n o de espera ocupada y cerrojos. Estructura dicha soluci´n como un par de subrutinas (usando una misma o estructura de datos en memoria compartida), una para el protocolo de entrada y otro el de salida, e incluye el pseudoc´digo de las mismas. o 16 Para calcular el n´mero combinatorio u n n(n − 1)(n − 2) . . . (n − k + 1) ( ) = k k! creamos un programa con dos procesos. El proceso P1 calcula el numerador y deposita el resultado en una variable compartida, denominada x, mientras que P2 calcula el factorial (el denominador) y deposita el valor en la variable y. Sincroniza los procesos P1 y P2 , utilizando sem´foros, para que el proceso P2 realice a correctamente la divisi´n x/y. o § var n : integer := .... ; k : integer := .... ; x : integer := 1 ; ¦ § process P1 begin for i := n-k+1 to n do x := x * i ; end ¦ 17 ¤ ¤ § process P2 ; var y : integer := 1 ; begin for j := 2 to k do y := y * j ; ¥ print( x/y ); end ¦ ¥ ¤ ¥ Sean los procesos P1 , P2 y P3 , cuyas secuencias de instrucciones son las que se muestran en el cuadro. Resuelva los siguientes problemas de sincronizaci´n (son independientes unos de otros): o creado October 4, 2013- p´gina 84 / 222 a
  • 85. SCD (13-14). Tema 2. Sincronizaci´n en memoria compartida.. o a) P2 podr´ pasar a ejecutar e solo si P1 ha ejecutado a o P3 ha ejecutado g. a b) P2 podr´ pasar a ejecutar e solo si P1 ha ejecutado a y P3 ha ejecutado g. a c) Solo cuando P1 haya ejecutado b, podr´ pasar P2 a ejecutar e y P3 a ejecutar h. a d) Sincroniza los procesos de forma que las secuencias b en P1 , f en P2 , y h en P3 , sean ejecutadas como mucho por dos procesos simult´neamente. a § { variables globales } ¦ § process P1 ; begin while true do begin a b c end end ¦ ¤ ¤ § process P2 ; begin while true do begin d e f end end ¥ ¦ ¤ § process P3 ; begin while true do begin g h i end end ¥ ¦ ¥ ¤ ¥ 18 Dos procesos P1 y P2 se pasan informaci´n a trav´s de una estructura de datos, ED. Sea un entero, n, o e que indica en todo momento el n´mero de elementos utiles en ED y cuyo valor inicial es 0. El proceso P2 u ´ retira de ED en cada ejecuci´n el ultimo elemento depositado por P1 , y espera si no hay elementos a que P2 o ´ ponga m´s. Sup´n que ED tiene un tama˜o ilimitado, es decir, es lo suficientemente grande para que nunca a o n se llene. Completa el c´digo de la figura usando sincronizaci´n con sem´foros de forma que el programa o o a cumpla la funci´n indicada. o § var ED : array[ 0..∞ ] of integer ; ¦ § process P1 ; var dato : integer; begin while true do begin dato := calcular(); n := n+1 ; ED[n] := dato ; end end ¦ 19 ¤ ¤ § process P1 ; var dato : integer; begin while true do begin dato := ED[n] ; n := n-1 ; usar( dato ); end end ¥ ¦ ¥ ¤ ¥ El cuadro que sigue nos muestra dos procesos concurrentes, P1 y P2 , que comparten una variable global x (las restantes variables son locales a los procesos). creado October 4, 2013- p´gina 85 / 222 a
  • 86. SCD (13-14). Tema 2. Sincronizaci´n en memoria compartida.. o a) Sincronizar los procesos para que P1 use todos los valores x suministrados por P2 . b) Sincronizar los procesos para que P1 utilice un valor s´ y otro no de la variable x, es decir, utilice los ı valores primero, tercero, quinto, etc... § { variables globales } ¦ § process P1 ; var m : integer ; begin while true do begin m := 2*x-n ; print( m ); end end ¦ ¤ ¤ § process P2 var d : integer ; begin while true do begin d := leer_teclado(); x := d-c*5 ; end end ¥ ¦ ¥ ¤ ¥ 20 En la f´brica de bicicletas MountanenBike, tenemos tres operarios que denominaremos OP1 , OP2 y OP3 . a OP1 hace ruedas (procedimiento h_rue), OP2 construye cuadros de bicicletas (h_cua), y OP3 , manillares (h_mani). Un cuarto operario, el Montador, se encarga de tomar dos ruedas (c_rue) , un cuadro (c_cua) y un manillar (c_man), y de hacer la bicicleta (h_bic). Sincroniza las acciones de los tres operarios y el montador en los siguientes casos: a) Los operarios no tienen ning´n espacio para almacenar los componentes producidos, y el Montador no u podr´ coger ninguna pieza si ´sta no ha sido fabricada previamente por el correspondiente operario. a e b) Los operarios OP2 y OP3 tienen espacio para almacenar 10 piezas de las que producen, por tanto, deben esperar si habiendo producido 10 piezas no es retirada ninguna por el Montador. El operador OP1 tiene espacio para 20 piezas. § { variables globales } ¦ § process OP1 ; begin while true do begin h_rue(); end end ¦ ¤ § ¤ process OP2 ; begin while true do begin h_cua(); end end ¦ ¥ § ¤ process OP3 ; begin while true do begin h_man(); end end ¦ ¥ § ¤ process OP4 ; begin while true do begin c_rue(); c_rue(); c_cua(); ¥ c_man(); m_bic(); end end ¦ ¥ ¤ ¥ creado October 4, 2013- p´gina 86 / 222 a
  • 87. SCD (13-14). Tema 2. Sincronizaci´n en memoria compartida.. o 21 Sentados en una mesa del Restaurante Atreveteacomer, est´n dos personas, cada una de las cuales esta a tomando un plato de sopa, y entre las dos comparten una fuente de ensalada. Estas dos personas no tienen mucha confianza y no pueden comer las dos simult´neamente del plato de ensalada. Se pide: a a) Dise˜ar un programa que resuelva el problema. n b) Ahora, sup´n que existe un camarero encargado de retirar los platos de sopa cuando ´stos est´n o e a vac´ es decir, cuando cada una de las personas ha tomado diez cucharadas. Soluciona esta variante ıos, teniendo en cuenta que el camarero debe cambiar los platos a las dos personas a la vez. § { variables globales compartidas } ¦ § ¤ § process Comensal_1 ; process Comensal_2 ; begin begin while true do begin while true do begin tomar_cucharada(); tomar_cucharada(); comer_ensalada(); comer_ensalada(); end end end end ¦ ¥ ¦ ¤ ¤ § { (apartado b) } process Camarero ; begin while true do begin quitar_sopa(); poner_sopa(); end ¥ end ¦ ¥ ¤ ¥ 22 Aunque un monitor garantiza la exclusi´n mutua, los procedimientos tienen que ser reentrantes. Explicar o porqu´. e 23 Se consideran dos recursos denominados r1 y r2 . Del recurso r1 existen N1 ejemplares y del recurso r2 existen N2 ejemplares. Escribir un monitor que gestione la asignaci´n de los recursos a los procesos de o usuario, suponiendo que cada proceso puede pedir: • Un ejemplar del recurso r1 . • Un ejemplar del recurso r2 . • Un ejemplar del recurso r1 y otro del recurso r2 . La soluci´n deber´ satisfacer estas dos condiciones: o a • Un recurso no ser´ asignado a un proceso que demande un ejemplar de r1 o un ejemplar de r2 hasta a que al menos un ejemplar de dicho recurso quede libre. creado October 4, 2013- p´gina 87 / 222 a
  • 88. SCD (13-14). Tema 2. Sincronizaci´n en memoria compartida.. o • Se dar´ prioridad a los procesos que demanden un ejemplar de ambos recursos. a • Se asume sem´ntica SU. a 24 Escribir una soluci´n al problema de lectores-escritores con monitores: o a) Con prioridad a los lectores. b) Con prioridad a los escritores. c) Con prioridades iguales. 25 Varios coches que vienen del norte y del sur pretenden cruzar un puente sobre un r´ Solo existe un carril ıo. sobre dicho puente. Por lo tanto, en un momento dado, el puente solo puede ser cruzado por uno o m´s a coches en la misma direcci´n (pero no en direcciones opuestas). o a) Completar el c´digo del siguiente monitor que resuelve el problema del acceso al puente suponiendo o que llega un coche del norte (sur) y cruza el puente si no hay otro coche del sur (norte) cruzando el puente en ese momento. § Monitor Puente var ... ; creado October 4, 2013- p´gina 88 / 222 a ¤
  • 89. SCD (13-14). Tema 2. Sincronizaci´n en memoria compartida.. o procedure begin ... end procedure begin .... end procedure begin .... end procedure begin ... end EntrarCocheDelNorte() SalirCocheDelNorte() EntrarCocheDelSur() SalirCocheDelSur() { Inicializacion } begin .... end ¦ ¥ b) Mejorar el monitor anterior, de forma que la direcci´n del trafico a trav´s del puente cambie cada vez o e que lo hayan cruzado 10 coches en una direcci´n, mientras 1 ´ m´s coches estuviesen esperando cruzar o o a el puente en direcci´n opuesta. o 26 Una tribu de antrop´fagos comparte una olla en la que caben M misioneros. Cuando alg´n salvaje quiere o u comer, se sirve directamente de la olla, a no ser que ´sta est´ vac´ Si la olla est´ vac´ el salvaje despertar´ e e ıa. a ıa, a al cocinero y esperar´ a que ´ste haya rellenado la olla con otros M misioneros. a e Para solucionar la sincronizacion usamos un monitor llamado Olla, que se puede usar as´ ı: § monitor Olla ; .... begin .... end ¦ § process ProcSalvaje[ i:1..N ] ; begin while true do begin Olla.Servirse_1_misionero(); Comer(); { es un retraso aleatorio } end end ¦ ¤ § process ProcCocinero ; begin while true do begin Olla.Dormir(); Olla.Rellenar_Olla(); end end ¥ ¦ ¤ ¥ ¤ ¥ creado October 4, 2013- p´gina 89 / 222 a
  • 90. SCD (13-14). Tema 2. Sincronizaci´n en memoria compartida.. o Dise˜a el c´digo del monitor Olla para la sincronizaci´n requerida, teniendo en cuenta que: n o o • La soluci´n no debe producir interbloqueo. o • Los salvajes podr´n comer siempre que haya comida en la olla, a • Solamente se despertar´ al cocinero cuando la olla est´ vac´ a e ıa. 27 Una cuenta de ahorros es compartida por varias personas (procesos). Cada persona puede depositar o retirar fondos de la cuenta. El saldo actual de la cuenta es la suma de todos los dep´sitos menos la suma o de todos los reintegros. El saldo nunca puede ser negativo. a) Programar un monitor para resolver el problema, todo proceso puede retirar fondos mientras la cantidad solicitada c sea menor o igual que el saldo disponible en la cuenta en ese momento. Si un proceso intenta retirar una cantidad c mayor que el saldo, debe quedar bloqueado hasta que el saldo se incremente lo suficiente (como consecuencia de que otros procesos depositen fondos en la cuenta) para que se pueda atender la petici´n. El monitor debe tener 2 procedimientos: depositar(c) y o retirar(c). Suponer que los argumentos de las 2 operaciones son siempre positivos. Hacer dos versiones: uno sin colas de prioridad y otra con colas de prioridad. b) Modificar la respuesta del apartado anterior, de tal forma que el reintegro de fondos a los clientes sea servido seg´n un orden FIFO. Por ejemplo, suponer que el saldo es 200 unidades y un cliente est´ u a esperando un reintegro de 300 unidades. Si llega otro cliente debe esperarse, incluso si quiere retirar 200 unidades. Resolver el problema usando un monitor con colas de prioridad. 28 Los procesos P1 , P2 ,...,Pn comparten un unico recurso R, pero solo un proceso puede utilizarlo cada vez. Un ´ proceso Pi puede comenzar a utilizar R si est´ libre; en caso contrario, el proceso debe esperar a que el a recurso sea liberado por otro proceso. Si hay varios procesos esperando a que quede libre R, se conceder´ a al proceso que tenga mayor prioridad. La regla de prioridad de los procesos es la siguiente: el proceso Pi tiene prioridad i, (con 1 ≤ i ≤ n), donde los n´meros menores implican mayor prioridad. Implementar un u monitor que implemente los procedimientos Pedir y Liberar. 29 En un sistema hay dos tipos de procesos: A y B. Queremos implementar un esquema de sincronizaci´n en o el que los procesos se sincronizan por bloques de 1 proceso del tipo A y 10 procesos del tipo B. De acuerdo con este esquema: • Si un proceso de tipo A llama a la operaci´n de sincronizaci´n, y no hay (al menos) 10 procesos de o o tipo B bloqueados en la operaci´n de sincronizaci´n, entonces el proceso de tipo A se bloquea. o o creado October 4, 2013- p´gina 90 / 222 a
  • 91. SCD (13-14). Tema 2. Sincronizaci´n en memoria compartida.. o • Si un proceso de tipo B llama a la operaci´n de sincronizaci´n, y no hay (al menos) 1 proceso del tipo o o A y 9 procesos del tipo B (aparte de ´l mismo) bloqueados en la operaci´n de sincronizaci´n, entonces e o o el proceso de tipo B se bloquea. • Si un proceso de tipo A llama a la operaci´n de sincronizaci´n y hay (al menos) 10 procesos bloqueados o o en dicha operaci´n, entonces el proceso de tipo A no se bloquea y adem´s deber´n desbloquearse o a a exactamente 10 procesos de tipo B. Si un proceso de tipo B llama a la operaci´n de sincronizaci´n y o o hay (al menos) 1 proceso de tipo A y 9 procesos de tipo B bloqueados en dicha operaci´n, entonces o el proceso de tipo B no se bloquea y adem´s deber´n desbloquearse exactamente 1 proceso del tipo a a A y 9 procesos del tipo B. • No se requiere que los procesos se desbloqueen en orden FIFO. los procedimientos para pedir y liberar el recurso Implementar un Monitor que implemente procedimientos para llevar a cabo la sincronizaci´n requerida entre o los diferentes tipos de procesos (el monitor puede exportar una unica operaci´n de sincronizaci´n para todos ´ o o los tipos de procesos o una operaci´n espc´ o ıfica para los de tipo A y otra para los de tipo B. 30 El siguiente monitor (Barrera2) proporciona un unico procedimiento de nombre entrada que provoca que ´ el primer proceso que lo llama sea suspendido y el segundo que lo llama despierte al primero que lo llam´, o y as´ act´a c´ ı u ıclicamente. Obtener una implementaci´n de este monitor usando sem´foros. o a § Monitor Barrera2 ; var n : integer; s : condicion ; { num. de proc. que han llegado desde el signal } { cola donde espera el segundo } procedure entrada() ; begin n := n+1 ; { ha llegado un proceso mas } if n<2 then { si es el primero: } s.wait() { esperar al segundo } else begin { si es el segundo: } n := 0; { inicializa el contador } s.signal() { despertar al primero } end end { Inicializacion } begin n := 0 ; end ¦ 31 ¤ ¥ Problema de los fil´sofos-comensales. Sentados a una mesa est´n cinco fil´sofos. La actividad de cada o a o creado October 4, 2013- p´gina 91 / 222 a
  • 92. SCD (13-14). Tema 3. Sistemas basados en paso de mensajes.. fil´sofo es un ciclo sin fin de las operaciones de pensar y comer. Entre cada dos fil´sofos hay un tenedor. o o Para comer, un fil´sofo necesita obligatoriamente dos tenedores: el de su derecha y el de su izquierda. Se o han definido cinco procesos concurrentes, cada uno de ellos describe la actividad de un fil´sofo. Los procesos o usan un monitor, llamado MonFilo. Antes de comer cada fil´sofo debe disponer de su tenedor de la derecha y el de la izquierda, y cuando o termina la actividad de comer, libera ambos tenedores. El fil´sofo i alude al tenedor de su derecha como el o n´mero i, y al de su izquierda como el n´mero i + 1 mod 5. u u El monitor MonFilo exportar´ dos procedimentos: coge_tenedor(num_tenedor,num_proceso) y libera_tenedor(n a para indicar que un proceso fil´sofo desea coger un tenedor determinado. o El c´digo del programa es el siguiente: o § monitor MonFilo ; .... begin .... end ¤ process Filosofo[ i: 0..4 ] ; begin while true do begin MonFilo.coge_tenedor(i,i); { argumento 1=codigo tenedor } MonFilo.coge_tenedor(i+1 mod 5, i); { argumento 2=numero de proceso } comer(); MonFilo.libera_tenedor(i,i); MonFilo.libera_tenedor(i+1 mod 5,i); pensar(); end end ¦ Dise˜a el monitor MonFilo, compartido por todos los procesos fil´sofos. Para evitar interbloqueo (que ocurre n o si todos los fil´sofos toman el tenedor a su izquierda antes de que ninguno de ellos pueda coger el tenedor o de la derecha), la soluci´n no debe permitir que haya m´s de cuatro fil´sofos simult´neamente intentado o a o a coger un tenedor creado October 4, 2013- p´gina 92 / 222 a ¥
  • 93. Chapter 4 Tema 3. Sistemas basados en paso de mensajes. 4.1 4.1.1 Mecanismos b´sicos en sistemas basados en paso de mensajes a Introducci´n o Introducci´n. Multiprocesador con mem. compartida vs. Sistema Distribuido o • Multiprocesador: ◾ M´s f´cil programaci´n (variables compartidas): se usan mecanismos como cerrojos, sem´foros y a a o a monitores. ◾ Implementaci´n m´s costosa y escalabilidad hardware limitada: el acceso a memoria com´n o a u supone un cuello de botella. • Sistema Distribuido: ◾ Distribuci´n de datos y recursos. o ◾ Soluciona el problema de la escalabilidad y el elevado coste. ◾ Mayor dificultad de programaci´n: No hay direcciones de memoria comunes y mecanismos como o los monitores son inviables. 93
  • 94. SCD (13-14). Tema 3. Sistemas basados en paso de mensajes.. Necesidad de una notaci´n de progr. distribuida o • Lenguajes tradicionales (memoria com´n) u ◾ Asignaci´n: Cambio del estado interno de la m´quina. o a ◾ Estructuraci´n: Secuencia, repetici´n, alternaci´n, procedimientos, etc. o o o • Extra a˜adido: Env´ / Recepci´n n ıo o ⇒ Afectan al entorno externo. ◾ Son tan importantes como la asignaci´n. o ◾ Permiten comunicar procesos que se ejecutan en paralelo. • Paso de mensajes: ◾ Abstracci´n: Oculta Hardware (red de interconexi´n). o o ◾ Portabilidad: Se puede implementar eficientemente en cualquier arquitectura (multiprocesador o plataforma distribuida). 4.1.2 ◾ No requiere mecanismos para asegurar la exclusi´n mutua. o Vista logica arquitectura y modelo de ejecuci´n o Vista logica de la arquitectura • N procesos, cada uno con su espacio de direcciones propio (memoria). • En un mismo procesador podr´ residir f´ ıan ısicamente varios procesos, aunque es muy com´n la ejecuci´n u o 1 proceso-procesador. • Los procesos se comunican mediante env´ y recepci´n de mensajes. ıo o • Cada interacci´n requiere cooperaci´n entre 2 procesos: el propietario de los datos (emisor) debe o o intervenir aunque no haya conexi´n l´gica con el evento tratado en el receptor. o o creado October 4, 2013- p´gina 94 / 222 a
  • 95. SCD (13-14). Tema 3. Sistemas basados en paso de mensajes.. Estructura de un programa de paso de mensajes. SPMD • Ejecutar un programa diferente sobre cada proceso puede ser algo dif´ de manejar. ıcil • Enfoque com´n: Estilo SPMD (Single Program Multiple Data). u ◾ El c´digo que ejecutan los diferentes procesos es id´ntico, pero sobre datos diferentes. o e ◾ El c´digo incluye la l´gica interna para que cada tarea ejecute lo que proceda dependiendo de o o la identidad del proceso. § { ejemplo: Proceso[0] envia y Proceso[1] recibe } process Proceso[ nump : 0..1 ]; begin if nump = 0 then begin {si soy 0} dato := Produce(); send( dato, Proceso[1]); end else begin {si soy 1} receive( dato, Proceso[0] ); Consume( dato ); end end ¦ Estructura de un programa de paso de mensajes. MPMD • Estilo MPMD (Multiple Program Multiple Data): ◾ Cada proceso ejecuta el mismo o diferentes programas de un conjunto de ficheros objeto ejecutables. ◾ Los diferentes procesos pueden usar datos diferentes. 4.1.3 Primitivas b´sicas de paso de mensajes a Primitivas b´sicas de paso de mensajes a • Env´ send(expresion,identi f icador proceso destino) ıo: creado October 4, 2013- p´gina 95 / 222 a ¤ ¥
  • 96. SCD (13-14). Tema 3. Sistemas basados en paso de mensajes.. • Recepci´n: receive(variable,identi f icador proceso origen) o Las primitivas send y receive permiten: • Comunicaci´n: Los procesos env´ o ıan/reciben mensajes en lugar de escribir/leer en variables compartidas. • Sincronizaci´n: la recepci´n de un mensaje es posterior al env´ Generalmente, la recepci´n supone o o ıo. o la espera del mensaje por parte del receptor. Esquemas de identificaci´n de la comunicaci´n o o ¿C´mo identifica el emisor al receptor del mensaje y viceversa? o Existen dos posibilidades: Denominaci´n directa o • Emisor identifica expl´ ıcitamente al receptor y viceversa. • Se utilizan los identificadores de los procesos. Denominaci´n indirecta o Los mensajes se depositan en almacenes intermedios que son globales a los procesos (buzones). Denominaci´n directa o • Ventaja principal: No hay retardo para establecer la identificaci´n. o • Inconvenientes: ◾ Cambios en la identificaci´n requieren recompilar el c´digo. o o ◾ S´lo permite enlaces 1-1. o creado October 4, 2013- p´gina 96 / 222 a
  • 97. SCD (13-14). Tema 3. Sistemas basados en paso de mensajes.. § process P0 ; var dato : integer ; begin dato := Produce(); send( dato, P1 ); end ¦ ¤ § process P1 ; var midato : integer ; begin receive( midato, P0 ); Consume( midato ); end ¥ ¦ ¤ ¥ • Existen esquemas asim´tricos: el emisor identifica al receptor, pero el receptor no indica emisor: e ◾ receive(variable,id origen): en id origen se devuelve el emisor del mensaje. ◾ receive(variable,ANY): ANY indica que se puede recibir de cualquier emisor. Denominaci´n indirecta o • Presenta una mayor flexibilidad al permitir la comunicaci´n simult´nea entre varios procesos. o a • Declaraci´n est´tica/din´mica: o a a ◾ Est´tica: fija fuente/destino en tiempo de compilaci´n. No apropiada en entornos cambiantes. a o ◾ Din´mica: m´s potente pero menos eficiente a a § var buzon : channel of integer ; ¦ § process P0 ; var dato : integer ; begin dato := Produce(); send( dato, buzon ); end ¦ ¤ § process P1 ; var midato : integer ; begin receive( midato, buzon ); Consume( midato ); end ¥ ¦ ¤ ¥ ¤ ¥ Denominaci´n indirecta (2) o • Existen tres tipos de buzones: canales (uno a uno), puertos (muchos a uno) y buzones generales (muchos a muchos). creado October 4, 2013- p´gina 97 / 222 a
  • 98. SCD (13-14). Tema 3. Sistemas basados en paso de mensajes.. Comportamiento de las operaciones de paso de mensajes • El comportamiento de las operaciones puede variar dependiendo de las necesidades. Ejemplo: § process Emisor ; var a : integer := 100 ; begin send( a, Receptor ) ; a := 0 ; end ¦ ¤ § process Receptor ; var b : integer ; begin receive( b, Emisor ) ; imprime( b ); end ¥ ¦ ¤ ¥ • El comportamiento esperado del send impone que el valor recibido en b sea el que ten´ a (100) justo ıa antes de la llamada a send. • Si se garantiza esto, se habla de comportamiento seguro (se habla de que el programa de paso de mensajes es seguro). • Generalmente, un programa no seguro (en el ejemplo, si pudiera recibirse 0 en lugar de 100), se considera incorrecto, aunque existen situaciones en las que puede interesar usar operaciones que no garantizan dicha seguridad. Instantes cr´ ıticos en las operaciones de paso de mensajes § process Emisor ; var a : integer := 100 ; begin send( a, Receptor ) ; a := 0 ; end ¦ Instantes relevantes en el emisor: ¤ § process Receptor ; var b : integer ; begin receive( b, Emisor ) ; imprime( b ); end ¥ ¦ ¤ ¥ creado October 4, 2013- p´gina 98 / 222 a
  • 99. SCD (13-14). Tema 3. Sistemas basados en paso de mensajes.. • E1 : Emisor acaba de indicar al Sistema de Paso de Mensajes (SPM) la direccion de a y el identificador del Receptor. • E2 : SPM comienza la lectura de datos en a. • E3 : SPM termina de leer todos los datos en a. Instantes relevanetes en el receptor: • R1 : Receptor acaba de indicar al SPM la direccion de b y el identificador del Emisor. • R2 : SPM comienza a escribir en b. • R3 : SPM termina de escribir en b. Ordenaci´n de los instantes relevantes o Los eventos relevantes citados deben ocurrir en cierto orden: • El emisor puede comenzar el envio antes que el receptor, o al rev´s. Es decir, no hay un orden temporal e entre E1 y R1 (se cumple E1 <= R1 o R1 <= E1 ). • L´gicamente, los tres eventos del emisor se producen en orden, y tambi´n los tres del receptor. Se o e cumple que: E1 < E2 < E3 y tambi´n que R1 < R2 < R3 . e • Antes de que se escriba el primer byte en el receptor, se debe haber comenzado ya la lectura en el emisor, por tanto E2 < R2 . • Antes de que se acaben de escribir los datos en el receptor, se deben haber acabado de leer en el emisor, es decir E3 < R3 . • Por transitividad se puede demostrar que R3 es siempre el ´ltimo evento. u Mensajes en tr´nsito a Por la hip´tesis de progreso finito, el intervalo de tiempo entre E1 y R3 tiene una duraci´n no predecible. o o Entre E1 y R3 , se dice que el mensaje est´ en tr´nsito. a a a e • El SPM necesita usar memoria temporal para todos los mensajes en tr´nsito que est´ gestionando en un momento dado. • La cantidad de memoria necesaria depender´ de diversos detalles (tama˜o y n´mero de los mensajes a n u en tr´nsito, velocidad de la transmisi´n de datos, pol´ a o ıticas de envio de mensajes, etc... ) • Dicha memoria puede estar ubicada en el nodo emisor y/o en el receptor y/o en nodos intermedios, si los hay. • En un momento dado, el SPM puede detectar que no tiene suficiente memoria para almacenamiento temporal de datos durante el envio (debe retrasar la lectura en el emisor hasta asegurarse que hay memoria para enviar los datos) creado October 4, 2013- p´gina 99 / 222 a
  • 100. SCD (13-14). Tema 3. Sistemas basados en paso de mensajes.. Seguridad de las operaciones de paso de mensajes Las operaciones de env´ y/o recepci´n podr´ no ser seguras, es decir, el valor que el emisor pretend´ ıo o ıan ıa enviar podr´ no ser el mismo que el receptor finalmente recibe, ya que se usan zonas de memoria, accesibles ıa desde los procesos involucrados, que podr´ escribirse cuando el mensaje est´ en tr´nsito. ıan a a • Operaci´n de env´ o ıo-recepci´n segura: Ocurre cuando se puede garantizar a priori que el valor de a o en E1 coincidir´ con el valor de b justo tras R3 . a • Operaci´n de env´ o ıo-recepci´n insegura: Una operaci´n puede ser no segura en dos circunstancias: o o ◾ se puede modificar el valor de a entre E1 y E3 (env´ inseguro) ıo ◾ se puede modificar el valor de b entre R2 y R3 (recepci´n insegura). o Tipos de operaciones de paso de mensajes Operaciones seguras • Devuelven el control cuando se garantiza la seguridad. • No siempre significa que el receptor haya recibido el dato cuando finalice el send, sino que cambiar los datos no viola la seguridad. • Existen 2 mecanismos de paso de mensajes seguro: ◾ Env´ y recepci´n s´ ıo o ıncronos. ◾ Env´ as´ ıo ıncrono seguro Operaciones inseguras • Devuelven el control de forma inmediata sin garantizar la seguridad. • Es responsabilidad del usuario asegurar que no se alteran los datos mientras el mensaje est´ en a tr´nsito. a • Deben existir sentencias adicionales para comprobar el estado de la operaci´n. o El est´ndar MPI incluye funciones con todas estos comportamientos. a Operaciones s´ ıncronas. Comportamiento § ¦ s send( variable , id proceso receptor ) ; ¥ • Realiza el env´ de los datos y espera bloqueado hasta que los datos hayan terminado de escribirse ıo en la memoria local designada por el proceso receptor en su llamada a la operaci´n de recepci´n. o o • Es decir: devuelve el control despu´s de R3 . e ¤ creado October 4, 2013- p´gina 100 / 222 a
  • 101. SCD (13-14). Tema 3. Sistemas basados en paso de mensajes.. § ¤ ¦ ¥ receive ( variable , id proceso emisor ) ; • Espera bloqueado hasta que el emisor emita un mensaje con destino al proceso receptor (si no lo hab´ ıa hecho ya), y hasta que hayan terminado de escribirse los datos en la zona de memoria designada en variable. • Es decir: devuelve el control despu´s de R3 . e Operaciones s´ ıncronas. Cita • Exige cita entre emisor y receptor: La operaci´n s_send no devuelve el control hasta que el receive o correspondiente sea alcanzado en el receptor ◾ El intercambio de mensaje constituye un punto de sincronizaci´n entre emisor y receptor. o ◾ El emisor podr´ hacer aserciones acerca del estado del receptor. a ◾ An´logo: comunicaci´n telef´nica y chat. a o o Operaciones s´ ıncronas. Desventajas • F´cil de implementar pero poco flexible. a • Sobrecarga por espera ociosa: adecuado s´lo cuando send/receive se inician aprox. mismo tiempo. o • Interbloqueo: es necesario alternar llamadas en intercambios (c´digo menos legible). o Ejemplo de Interbloqueo § { P0 } s_send( a, P1 ); receive( b, P0 ); ¦ Correcci´n o ¤ § { P0 } s_send( a, P1 ); receive( b, P0 ); ¦ ¤ ¥ ¥ § { P1 } s_send( a, P0 ); receive( b, P1 ); ¦ ¤ § { P1 } receive( b, P1 ); s_send( a, P0 ); ¦ ¤ ¥ ¥ creado October 4, 2013- p´gina 101 / 222 a
  • 102. SCD (13-14). Tema 3. Sistemas basados en paso de mensajes.. Env´ as´ ıo ıncrono seguro (1) § ¦ ¤ send( variable , id proceso receptor ) ; ¥ • Inicia el env´ de los datos designados y espera bloqueado hasta que hayan terminado de leerse todos ıo los datos de variable en una memoria local del Emisor (buffer). Tras la copia de datos a memoria local, devuelve el control sin que tengan que haberse recibido los datos en el receptor. • Por tanto, devuelve el control despu´s de E3 . e • Se suele usar junto con la recepci´n s´ o ıncrona (receive). Env´ as´ ıo ıncrono seguro. Ventajas e Inconvenientes • Alivia sobrecargas de espera ociosa a costa de gesti´n de almacenamiento temporal (buffer). o • S´lo menos ventajosas en programas altamente s´ o ıncronos o cuando la capacidad del buffer sea un asunto cr´ ıtico. • Impacto del buffer finito: Se deben escribir programas con requisitos de almacenamiento acotados. ◾ Si P1 es m´s lento que P0, P0 podr´ continuar siempre que hubiese buffer. Si el buffer se agota, a ıa P0 se bloquear´ ıa. § { P0 } for i:=1 to 10000 do begin a := Produce() ; send( a, P1 ) ; end ¦ ¤ § { P1 } for i:=1 to 10000 do begin receive( a, P0 ) ; Consume( a ) ; end ¥ ¦ • Interbloqueo con buffer: No olvidar que las llamadas a receive siguen siendo s´ ıncronas. § { P0 } receive( b, P1 ); send( a, P1 ); ¦ ¤ ¥ § receive( b, P0 ); { P1 } send( a, P0 ); ¦ ¤ ¥ creado October 4, 2013- p´gina 102 / 222 a ¤ ¥
  • 103. SCD (13-14). Tema 3. Sistemas basados en paso de mensajes.. Operaciones inseguras • Operaciones seguras: Garantizan la seguridad, pero presentan ineficiencias: ◾ sobrecarga de espera ociosa (sin buffer). ◾ sobrecarga de gesti´n de buffer (con buffer). o • Alternativa: Requerir que el programador asegure la correcci´n y usar operaciones send/receive o con baja sobrecarga. ◾ Las operaciones devuelven el control antes de que sea seguro modificar (en el caso del env´ o ıo) leer los datos (en el caso de la reepci´n). o ◾ Es responsabilidad del usuario asegurar que el comportamiento es correcto. ◾ Deben existir sentencias de chequeo de estado: indican si los datos pueden alterarse o leerse sin comprometer la seguridad. ◾ Una vez iniciada la operaci´n, el usuario puede realizar cualquier c´mputo que no dependa de la o o finalizaci´n de la operaci´n y, cuando sea necesario, chequear´ el estado de la operaci´n. o o a o Paso de mensajes as´ ıncrono inseguro. Operaciones § ¦ i send( variable , id proceso receptor , var resguardo ) ; ¤ ¥ • Indica al SPM que comienze una operaci´n de env´ al proceso receptor designado. No espera a que o ıo terminen de leerse los bytes del emisor, ni a que terminen de escribirse en el receptor. • Es decir: devuelve el control despu´s de E1 . e § ¦ • var resguardo permite consultar el estado del env´ ıo. ¤ i receive ( variable , id proceso receptor , var resguardo ) ; ¥ • Indica al SPM que el proceso receptor desea recibir en la zona de memoria local designada en variable un mensaje del proceso emisor indicado. Se devuelve el control sin esperar a que se complete el env´ ıo ni a que llegen los datos. • Es decir: devuelve el control despu´s de R1 . e • var resguardo permite consultar despu´s el estado de la recepci´n. e o Esperar el final de operaciones as´ ıncronas Cuando un proceso hace i_send o i_receive puede continuar trabajando hasta que llega un momento en el que debe esperar a que termine la operaci´n. Para esto se disponen de estos dos procedimientos: o § ¦ wait send( var resguardo ) ; creado October 4, 2013- p´gina 103 / 222 a ¤ ¥
  • 104. SCD (13-14). Tema 3. Sistemas basados en paso de mensajes.. § ¦ • Se invoca por el proceso emisor, y lo bloquea hasta que la operaci´n de env´ asociada a var resguardo o ıo ha llegado al instante E3 . wait recv ( var resguardo ) ; • Se invoca por el proceso receptor, que queda bloqueado hasta que la operaci´n de recepci´n asociada o o a var resguardo ha llegado al instante R3 . Paso de mensajes as´ ıncrono inseguro (no bloqueante) • El proceso que ejecuta i_send informa al SPM de un mensaje pendiente y contin´a. u ◾ El programa puede hacer mientras otro trabajo (trabajo_util) ◾ El SPM iniciar´ la comunicaci´n cuando corresponda. a o ◾ Operaciones de chequeo indican si es seguro tocar/leer los datos. • Mejora: El tiempo de espera ociosa se puede emplear en computaci´n o • Coste: Reestructuraci´n programa, mayor esfuerzo del programador. o § process Emisor ; var a : integer := 100 ; begin i_send( a, Receptor, resg ); { trabajo util : no escribe en ’ a’} trabajo_util_emisor(); wait_send(resg); a := 0 ; end ¦ ¤ § process Receptor ; var b : integer ; begin i_receive( b, Emisor, resg ); { trabajo util : no accede a ’ b’} trabajo_util_receptor(); wait_recv (resg); imprime( b ); end ¥ ¦ Ejemplo: Productor-Consumidor con paso as´ ıncrono Se logra simultanear transmisi´n, producci´n y consumici´n: o o o § process Productor ; var x, x_env : integer ; begin x := Producir() while true do begin x_env := x ; i_send(x_env,Consumidor,resg); x := Producir() ; wait_send(resg); end end ¦ ¤ § process Consumidor ; var y, y_rec : integer ; begin i_receive(y_rec,Productor,resg); while true do begin wait_recv(resg); y := y_rec ; i_receive(y_rec,Productor,resg); Consumir(y); end end ¥ ¦ ¤ ¥ ¤ ¥ creado October 4, 2013- p´gina 104 / 222 a ¤ ¥
  • 105. SCD (13-14). Tema 3. Sistemas basados en paso de mensajes.. Limitaciones: • La duraci´n del trabajo util podr´ ser muy distinta de la de cada transmisi´n. o ıa o • Se descarta la posibilidad de esperar m´s de un posible emisor. a Consulta de estado de operaciones as´ ıncronas Para solventar los dos problemas descritos, se pueden usar dos funciones de comprobaci´n de estado de una o transmisi´n de un mensaje. No suponen bloqueo, solo una consulta: o § ¦ § ¦ test send ( var resguardo ) ; • Funci´n l´gica que se invoca por el emisor. Si el env´ asociado a var resguardo ha llegado a E3 , o o ıo devuelve true, sino devuelve false. test recv ( var resguardo) ; • Funci´n l´gica que se invoca por el receptor. Si el env´ asociado a var resguardo ha llegado a R3 , o o ıo devuelve true, sino devuelve false. Paso as´ ıncrono con espera ocupada posterior. El trabajo util de nuevo se puede simult´near con la transmisi´n del mensaje, pero en este caso dicho debe a o descomponerse en muchas tareas peque˜as. n § process Emisor ; var a : integer := 100 ; begin i_send( a, Receptor, resg ); while not test_send( resg ) do { trabajo util : no escribe en ’ a’} trabajo_util_emisor(); a := 0 ; end ¦ ¤ § process Receptor ; var b : integer ; begin i_receive( b, Emisor, resg ); while not test_recv( resg ) do { trabajo util : no accede a ’ b’} trabajo_util_receptor(); imprime( b ); end ¥ ¦ ¤ ¥ Si el trabajo util es muy corto, puede convertirse en una espera ocupada que consume much´ ısima CPU in´tilmente. Es complejo de ajustar bien. u Recepci´n simult´nea de varios emisores. o a En este caso se comprueba continuamente si se ha recibido un mensaje de uno cualquiera de dos emisores, y se espera hasta que se han recibido de los dos: creado October 4, 2013- p´gina 105 / 222 a ¤ ¥ ¤ ¥
  • 106. SCD (13-14). Tema 3. Sistemas basados en paso de mensajes.. § process Emisor1 ; var a :integer:= 100; begin send(a,Receptor); end process Emisor2 ; var b :integer:= 200; begin send(b,Receptor); end ¦ 4.1.4 ¤§ process Receptor ; var b1, b2 : integer ; r1,r2 : boolean := false ; begin i_receive( b1, Emisor1, resg1 ); i_receive( b2, Emisor2, resg2 ); while not r1 or not r2 do begin if not r1 and test_recv( resg1 ) then begin r1 := true ; imprime(" recibido de 1 : ", b1 ); end ¥ if not r2 and test_recv( resg2 ) then begin r2 := true ; imprime(" recibido de 2 : ", b2 ); end end end ¦ ¤ ¥ Espera selectiva Espera Selectiva. Introducci´n al problema o • Los modelos basados en paso de mensajes imponen ciertas restricciones. • No basta con send y receive para modelar el comportamiento deseado. Productor-Consumidor con buffer de tama˜o fijo n • Se asumen operaciones s´ ıncronas. • Problema: Acoplamiento forzado entre los procesos. § process Productor ; begin while true do begin v := Produce(); s_send(v,Consumidor); end end ¦ ¤ ¥ § process Consumidor ; begin while true do begin receive(v,Productor); Consume(v); end end ¦ ¤ ¥ Introducci´n al problema. Mejora o • Mejora: Gesti´n intercambio mediante proceso Buffer. o ◾ Productor puede continuar despu´s env´ e ıo. ◾ Problema: El buffer s´lo puede esperar mensajes de un unico emisor en cada instante. o ´ creado October 4, 2013- p´gina 106 / 222 a
  • 107. SCD (13-14). Tema 3. Sistemas basados en paso de mensajes.. • Aspecto com´n en aplicaciones cliente-servidor. u ◾ No se conoce a priori el cliente que hace la petici´n en cada instante. o ◾ Servidor debe estar preparado para recibir sin importar orden. § { Productor (P) } process P ; begin while true do begin v:=Produce(); s_send(v,B); end end ¦ ¤ ¥ § { Buffer (B) } process B ; begin while true do begin receive(v,P); receive(s,C); s_send(v,C); end end ¦ ¤ ¥ § { Consumidor (C) } process C ; begin while true do begin s_send(s,B); receive(v,B); Consume(v); end end ¦ ¤ ¥ Espera selectiva con alternativas guardadas (1) Soluci´n: usar espera selectiva con varias alternativas guardadas. Es una nueva sentencia compuesta, con o la siguiente sintaxis: § select when condicion1 receive( variable1 , proceso1 ) do sentencias1 when condicion2 receive( variable2 , proceso2 ) do sentencias2 ⋯ when condicionn receive( variablen , proceson ) do sentenciasn end ¦ ¤ ¥ • Cada bloque que comienza en when se llama una alternativa. • En cada alternativa, el texto desde when hasta do se llama la guarda de dicha alternativa, la guarda puede incluir una expresi´n l´gica (condicioni ) o o • Los receive nombran a otros procesos del programa concurrente (procesoi ), y cada uno referencia una variable local (variablei ), donde eventualmente se recibir´ un valor del proceso asociado. a Sintaxis de las guardas. En una guarda de una orden select: • La expresi´n l´gica puede omitirse, es ese caso la sintaxis ser´ o o ıa: § when receive( mensaje, proceso ) do sentencias ¦ que es equivalente a: ¤ ¥ creado October 4, 2013- p´gina 107 / 222 a
  • 108. SCD (13-14). Tema 3. Sistemas basados en paso de mensajes.. § when true receive( mensaje, proceso ) do sentencias ¦ • La sentencia receive puede no aparecer, la sintaxis es: § when condicion do sentencias ¦ ¤ ¥ ¤ ¥ decimos que esta es una guarda sin sentencia de entrada. Guardas ejecutables. Evaluaci´n de las guardas. o Una guarda es ejecutable en un momento de la ejecuci´n de un proceso P cuando se dan estas dos condio ciones: • La condici´n de la guarda se eval´a en ese momento a true. o u • Si tiene sentencia de entrada, entonces el proceso origen nombrado ya ha iniciado en ese momento una sentencia send (de cualquier tipo) con destino al proceso P, que casa con el receive. Una guarda ser´ potencialmente ejecutable si se dan estas dos condiciones: a • La condici´n de la guarda se eval´a a true. o u • Tiene una sentencia de entrada, sentencia que nombra a un proceso que no ha iniciado a´n un send u hacia P. Una guarda ser´ no ejecutable en el resto de los casos, en los que forzosamente la condici´n de la guarda a o se eval´a a false. u Evaluaci´n de las guardas. o Cuando el flujo de control llega a un select, se eval´an las condiciones de todas las guardas, y se verifica u el estado de todos los procesos nombrados en los receive. De esta forma se clasifican las guardas, y se selecciona una alternativa: • Si hay guardas ejecutables con sentencia de entrada: se selecciona aquella cuyo send se inici´ antes o (esto garantiza a veces la equidad). • Si hay guardas ejecutables, pero ninguna tiene una sentencia de entrada: se selecciona aleatoriamente una cualquiera. • Si no hay ninguna guarda ejecutable, pero s´ hay guardas potencialmente ejecutables: se espera ı (bloqueado) a que alguno de los procesos nombrados en esas guardas inicie un send, en ese momento acaba la espera y se selecciona la guarda correspondiente a ese proceso. • Si no hay guardas ejecutables ni potencialmente ejecutables: no se selecciona ninguna guarda. creado October 4, 2013- p´gina 108 / 222 a
  • 109. SCD (13-14). Tema 3. Sistemas basados en paso de mensajes.. Ejecuci´n de un select o Para ejecutar un select primero se intenta seleccionar una guarda de acuerdo con el esquema descrito arriba. • Si no se puede seleccionar ninguna guarda, no se hace nada (no hay guardas ni ejecutables, ni potencialmente ejecutables). • Si se ha podido seleccionar una guarda, entonces se dan estos dos pasos en secuencia: 1. Si esa guarda tiene sentencia de entrada, se ejecuta el receive (siempre habr´ un send iniciado), a y se recibe el mensaje. 2. Se ejecuta la sentencia asociada a la alternativa. y despu´s finaliza la ejecuci´n del select. e o Hay que tener en cuenta que select conlleva potencialmente esperas, y por tanto se pueden producir esperas indefinidas (interbloqueo). Existe select con prioridad: la selecci´n no ser´ arbitraria (el orden en el que aparecen las alternativas o ıa establece la prioridad). Productor-Consumidor con buffer limitado • Buffer no conoce a priori orden de peticiones (Inserci´n/Extracci´n). o o • Las guardas controlan las condiciones de sincronizaci´n (seguridad). o § { Productor (P) } while true do begin v:=Produce(); s_send(v,B); end ¦ ¤ ¥ § { Buffer (B) } var esc, lec, cont : integer := 0 ; buf : array[0..tam-1] of integer ; begin while true do select when cont<=tam receive(v,P) do buf[esc]:= v ; esc := (esc+1) mod tam ; cont := cont+1 ; when cont ≠ 0 receive(s,C) do s_send(buf[lec],C); esc := (esc+tam-1) mod tam ; cont := cont-1 ; end end ¦ ¤ § { Consumidor (C) } while true do begin s_send(s,B); receive(v,B); Consume(v); end ¦ ¤ ¥ ¥ Select con guardas indexadas A veces es necesario replicar una alternativa. En estos casos se puede usar una sintaxis que evita reescribir el c´digo muchas veces, con esta sintaxis: o creado October 4, 2013- p´gina 109 / 222 a
  • 110. SCD (13-14). Tema 3. Sistemas basados en paso de mensajes.. § for indice := inicial to f inal when condicion receive( mensaje, proceso ) do sentencias ¦ ¥ Tanto la condici´n, como el mensaje, el proceso o la sentencia pueden contener referencias a la variable o indice (usualmente es i o j). Es equivalente a: § when condicion receive( mensaje, sentencias { se sustituye indice when condicion receive( mensaje, sentencias { se sustituye indice ⋯ when condicion receive( mensaje, sentencias { se sustituye indice ¦ ¤ proceso ) do por inicial } proceso ) do por inicial + 1 } proceso ) do por f inal } ¤ ¥ Ejemplo de select con guardas indexadas A modo de ejemplo, si suma es un vector de n enteros, y fuente[0], fuente[1], etc... son n procesos, entonces: § for i := 0 to n-1 when suma[i] < 1000 receive( numero, fuente[i] ) do suma[i] := suma[i] + numero ; ¦ Es equivalente a: § when suma[0] < 1000 receive( numero, fuente[0] ) do suma[0] := suma[0] + numero ; when suma[1] < 1000 receive( numero, fuente[1] ) do suma[1] := suma[1] + numero ; ⋯ when suma[n-1] < 1000 receive( numero, fuente[n − 1] ) do suma[n-1] := suma[n-1] + numero ; ¦ ¤ ¥ ¤ ¥ En un select se pueden combinar una o varias alternativas indexadas con alternativas normales no indexadas. Ejemplo de select Este ejemplo suma los primeros numeros recibidos de cada uno de los n procesos fuente hasta que cada suma iguala o supera al valor 1000: § var suma : array[0..n-1] of integer := (0,0,...,0) ; continuar : boolean := false ; numero : integer ; begin while continuar do begin continuar := false ; { terminar cuando ∀i suma[i] ≥ 1000 } select for i := 0 to n − 1 when suma[i] < 1000 receive( numero, fuente[i] ) do creado October 4, 2013- p´gina 110 / 222 a ¤
  • 111. SCD (13-14). Tema 3. Sistemas basados en paso de mensajes.. end end suma[i] := suma[i]+numero ; { sumar } continuar := true ; { iterar de nuevo } end ¦ ¥ aqu´ hemos supuesto que los procesos fuente est´n definidos como: ı a § process fuente[ i : 0..n − 1 ] ; begin ..... end ¦ 4.2 4.2.1 ¥ Paradigmas de interacci´n de procesos en programas distribuidos o Introducci´n o Introducci´n o Paradigma de interacci´n o Un paradigma de interacci´n define un esquema de interacci´n entre procesos y una estructura de control o o que aparece en m´ltiples programas. u • Unos pocos paradigmas de interacci´n se utilizan repetidamente para desarrollar muchos programas o distribuidos. • Veremos los siguientes paradigmas de interacci´n: o 1. Maestro-Esclavo. 2. Iteraci´n s´ o ıncrona. 3. Encauzamiento (pipelining). 4. Cliente-Servidor. • Se usan principalmente en programaci´n paralela, excepto el ultimo que es m´s general (sistemas o a distribuidos) y se ver´ en el siguiente apartado del cap´ a ıtulo (Mecanismos de alto nivel para paso de mensajes). 4.2.2 ¤ Maestro-Esclavo Maestro-Esclavo • En este patr´n de interacci´n intervienen dos entidades: un proceso maestro y m´ltiples procesos o o u esclavos. • El proceso maestro descompone el problema en peque˜as subtareas (que guarda en una colecci´n), n o las distribuye entre los procesos esclavos y va recibiendo los resultados parciales de estos, de cara a producir el resultado final. creado October 4, 2013- p´gina 111 / 222 a
  • 112. SCD (13-14). Tema 3. Sistemas basados en paso de mensajes.. • Los procesos esclavos ejecutan un ciclo muy simple hasta que el maestro informa del final del c´mputo: o reciben un mensaje con la tarea , procesan la tarea y env´ el resultado al maestro. ıan Ejemplo: C´lculo del Conjunto de Mandelbrot a • Conjunto de Mandelbrot: Conjunto de puntos c del plano complejo (dentro de un c´ ırculo de radio 2 centrado en el origen) que no exceder´n cierto l´ a ımite cuando se calculan realizando la siguiente iteraci´n (inicialmente z = 0 con z = a + bi ∈ C): o Repetir zk+1 = zk 2 + c hasta z > 2 o k > l´ ımite • Se asocia a cada pixel (con centro en el punto c) un color en funci´n del n´mero de iteraciones (k) o u necesarias para su c´lculo. a • Conjunto soluci´n= {pixels que agoten iteraciones l´ o ımite dentro de un c´ ırculo de radio 2 centrado en el origen}. Ejemplo: C´lculo del Conjunto de Mandelbrot a • Paralelizaci´n sencilla: Cada pixel se puede calcular sin ninguna informaci´n del resto o o • Primera aproximaci´n: asignar un n´mero de pixels fijo a cada proceso esclavo y recibir resultados. o u ◾ Problema: Algunos procesos esclavos tendr´ m´s trabajo que otros (el n´mero de iteraciones ıan a u por pixel no es fijo) para cada pixel. • Segunda aproximaci´n: o creado October 4, 2013- p´gina 112 / 222 a
  • 113. SCD (13-14). Tema 3. Sistemas basados en paso de mensajes.. ◾ El maestro tiene asociada una colecci´n de filas de pixels. o ◾ Cuando los procesos esclavos est´n ociosos esperan recibir una fila de pixels. a ◾ Cuando no quedan m´s filas, el Maestro espera a que todos los procesos completen sus tareas a pendientes e informa de la finalizaci´n del c´lculo. o a • Veremos una soluci´n que usa env´ as´ o ıo ıncrono seguro y recepci´n s´ o ıncrona. Procesos Maestro y Esclavo § process Maestro ; begin for i := 0 to num_esclavos-1 do send( fila, Esclavo[i] ) ; { enviar trabajo a esclavo } while queden filas sin colorear do select for j := 0 to ne − 1 when receive( colores, Esclavo[j] ) do if quedan filas en la bolsa then send( fila, Esclavo[j] ) else send( fin, Esclavo[j] ); visualiza(colores); end end ¦ § process Esclavo[ i : 0..num_esclavos-1 ] ; begin receive( mensaje, Maestro ); while mensaje != fin do begin colores := calcula_colores(mensaje.fila) ; send (colores, Maestro ); receive( mensaje, Maestro ); end end ¦ 4.2.3 Iteraci´n s´ o ıncrona Iteraci´n s´ o ıncrona • Iteraci´n: En m´ltiples problemas num´ricos, un c´lculo se repite y cada vez se obtiene un resultado o u e a que se utiliza en el siguiente c´lculo. El proceso se repite hasta obtener los resultados deseados. a • A menudo se pueden realizar los c´lculos de cada iteraci´n de forma concurrente. a o • Paradigma de iteraci´n s´ o ıncrona: ◾ En un bucle diversos procesos comienzan juntos en el inicio de cada iteraci´n. o ◾ La siguiente iteraci´n no puede comenzar hasta que todos los procesos hayan acabado la previa. o ◾ Los procesos suelen intercambiar informaci´n en cada iteraci´n. o o creado October 4, 2013- p´gina 113 / 222 a ¤ ¥ ¤ ¥
  • 114. SCD (13-14). Tema 3. Sistemas basados en paso de mensajes.. Ejemplo: Transformaci´n iterativa de un vector (1) o Supongamos que debemos realizar M iteraciones de un c´lculo que transforma un vector x de n reales: a xi−1 − xi + xi+1 , 2 (k) (k) x−1 = xn−1 , (k) xi (k+1) = (k) (k) i = 0, . . . , n − 1, k = 0, 1, . . . , N, x n = x0 . (k) (k) Veremos una soluci´n que usa env´ as´ o ıo ıncrono seguro y recepci´n s´ o ıncrona. Ejemplo: Transformaci´n iterativa de un vector (2) o El esquema que se usar´ para implementar ser´ este: a a • El n´mero de iteraciones es una constante predefinida m u • Se lanzan p procesos concurrentes. • Cada proceso guarda una parte del vector completo, esa parte es un vector local con n/p entradas reales, indexadas de 0 a n/p − 1 (vector bloque) (asumimos que n es m´ltiplo de p) u • Cada proceso, al inicio de cada iteraci´n, se comunica con sus dos vecinos las entradas primera y o ultima de su bloque. ´ • Al inicio de cada proceso, se leen los valores iniciales de un vector compartido que se llama valores (con n entradas), al final se copian los resultados en dicho vector. creado October 4, 2013- p´gina 114 / 222 a
  • 115. SCD (13-14). Tema 3. Sistemas basados en paso de mensajes.. Ejemplo: Transformaci´n iterativa de un vector (3) o El c´digo de cada proceso puede quedar as´ o ı: § process Tarea[ i : 0..p − 1 ] ; var bloque : array[0..n/p-1] of float ; { bloque local (no compartido) } begin for j := 0 to n/p-1 do bloque[j] := valores[i*n/p+j] ; { lee valores } for k := 0 to m do begin { bucle que ejecuta las iteraciones } { comunicacion de valores extremos con los vecinos } send( bloque[0] ,Tarea[i-1 mod p] ); { enviar primero a anterior } send( bloque[n/p-1],Tarea[i+1 mod p] ); { enviar ultimo a siguiente } receive( izquierda, Tarea[i-1 mod p] ); { recibir ultimo de anterior } receive( derecha, Tarea[i+1 mod p] ); { recibir primero del siguiente } { calcular todas las entradas excepto la ultima } for j := 0 to n/p-2 do begin tmp := bloque[j] ; bloque[j] := ( izquierda - bloque[j] + bloque[j+1] )/2; izquierda := tmp ; end { calcular ultima entrada } bloque[n/p-1] := ( izquierda - bloque[n/p-1] + derecha )/2; end for j := 0 to n/p-1 do valores[i*n/p+j] := bloque[j] ; { escribre resultados } end ¦ 4.2.4 ¤ ¥ Encauzamiento (pipelining) Encauzamiento (pipelining) • El problema se divide en una serie de tareas que se han de completar una despu´s de otra e • Cada tarea se ejecuta por un proceso separado. • Los procesos se organizan en un cauce (pipeline) donde cada proceso se corresponde con una etapa del cauce y es responsable de una tarea particular. • Cada etapa del cauce contribuir´ al problema global y devuelve informaci´n que es necesaria para a o etapas posteriores del cauce. • Patr´n de comunicaci´n muy simple ya que se establece un flujo de datos entre las tareas adyacentes o o en el cauce. Encauzamiento: Ejemplo (1) Cauce paralelo para filtrar una lista de enteros creado October 4, 2013- p´gina 115 / 222 a
  • 116. SCD (13-14). Tema 3. Sistemas basados en paso de mensajes.. • Dada una serie de m primos p0 , p1 , ..., pm−1 y una lista de n enteros, a0 , a1 , a2 , ..., an−1 , encontrar aquellos n´meros de la lista que son m´ltiplos de todos los m primos (n >> m) u u • El proceso Etapa[i] (con i = 0, . . . , m − 1) mantiene el primo pi y chequea multiplicidad con pi . • Veremos una soluci´n que usa operaciones s´ o ıncronas. Encauzamiento: Ejemplo (2) § { vector (compartido) con la lista de primos } var primos : array[0..m − 1] of float := { p0 , p1 , p2 , ⋯, pm−1 } ; ¤ { procesos que ejecutan cada etapa: } process Etapa[ i : 0..m − 1 ] ; var izquierda : integer := 0 ; begin while izquierda >= 0 do begin if i == 0 then leer( izquierda ); { obtiene siguiente entero } else receive( izquierda, Etapa[i-1]); if izquierda mod primos[i] == 0 then begin if i != m-1 then s_send ( izquierda, Etapa[i+1]); else imprime( izquierda ); end end end ¦ 4.3 4.3.1 ¥ Mecanismos de alto nivel en sistemas distribuidos Introducci´n o Introducci´n o • Los mecanismos vistos hasta ahora (varios tipos de env´ ıo/recepci´n espera selectiva, ...) presentan un o bajo nivel de abstracci´n. o creado October 4, 2013- p´gina 116 / 222 a
  • 117. SCD (13-14). Tema 3. Sistemas basados en paso de mensajes.. • Se ver´n dos mecanismos de mayor nivel de abstracci´n: Llamada a procedimiento remoto (RPC) e a o Invocaci´n remota de m´todos (RMI). o e • Est´n basados en la forma de comunicaci´n habitual en un programa: llamada a procedimiento. a o ◾ El llamador proporciona nombre del proc + par´metros, y espera. a ◾ Cuando proc. termina, el llamador obtiene los resultados y contin´a. u • En el modelo de invocaci´n remota: o ◾ El llamador invoca desde un proceso o m´quina diferente de donde se encuentra el procedimiento a invocado. ◾ El llamador se queda bloqueado hasta que recibe los resultados (esquema s´ ıncrono). ◾ El flujo de comunicaci´n es bidireccional (petici´n-respuesta). o o 4.3.2 ◾ Se permite que varios procesos invoquen un procedimiento gestionado por otro proceso (esquema muchos a uno). El paradigma Cliente-Servidor El paradigma Cliente-Servidor • Paradigma m´s frecuente en programaci´n distribuida. a o • Relaci´n asim´trica entre dos procesos: cliente y servidor. o e ◾ Proceso servidor: gestiona un recurso (por ejemplo, una base de datos) y ofrece un servicio a otros procesos (clientes) para permitir que puedan acceder al recurso. Puede estar ejecut´ndose a durante un largo periodo de tiempo, pero no hace nada util mientras espera peticiones de los ´ clientes. ◾ Proceso cliente: necesita el servicio y env´ un mensaje de petici´n al servidor solicitando algo ıa o asociado al servicio proporcionado por el servidor (p.e. una consulta sobre la base de datos). El paradigma Cliente-Servidor Es sencillo implementar esquemas de interacci´n cliente-servidor usando los mecanismos vistos. Para ello o usamos en el servidor un select que acepta peticiones de cada uno de los clientes: creado October 4, 2013- p´gina 117 / 222 a
  • 118. SCD (13-14). Tema 3. Sistemas basados en paso de mensajes.. § process Cliente[ i : 0..n − 1 ] ; begin while true do begin s_send( peticion, Servidor ); receive( respuesta, Servidor ); end end process Servidor ; begin while true do select for i:= 0 to n-1 when condicion[i] receive( peticion, Cliente[i] ) do respuesta := servicio( peticion ) ; s_send( respuesta, Cliente[i] ), end end ¦ ¤ ¥ Problemas de la soluci´n o No obstante, se plantean problemas de seguridad en esta soluci´n: o • Si el servidor falla, el cliente se queda esperando una respuesta que nunca llegar´. a • Si un cliente no invoca el receive(respuesta,Servidor) y el servidor realiza s_send(respuesta,Cliente[j] s´ ıncrono, el servidor quedar´ bloqueado a Para resolver estos problemas: • El par (recepci´n de petici´n, env´ de respuesta) se debe considerar como una unica operaci´n de o o ıo ´ o comunicaci´n bidireccional en el servidor y no como dos operaciones separadas. o • El mecanismo de llamada a procedimiento remoto (RPC) proporciona una soluci´n en esta l´ o ınea. 4.3.3 Llamada a Procedimiento (RPC) Introducci´n a RPC o • Llamada a procedimiento remoto (Remote Procedure Call): Mecanismo de comunicaci´n entre proo cesos que sigue el esquema cliente-servidor y que permite realizar las comunicaciones como llamadas a procedimientos convencionales (locales). • Diferencia ppal respecto a una llamada a procedimiento local: El programa que invoca el procedimiento (cliente) y el procedimiento invocado (que corre en un proceso servidor) pueden pertenecer a m´quinas diferentes del sistema distribuido. a creado October 4, 2013- p´gina 118 / 222 a
  • 119. SCD (13-14). Tema 3. Sistemas basados en paso de mensajes.. Esquema de interacci´n en una RPC o • Representante o delegado (stub): procedimiento local que gestiona la comunicaci´n en el lado del o cliente o del servidor. • Los procesos cliente y servidor no se comunican directamente, sino a trav´s de representantes. e Esquema general de una RPC. Inicio en el nodo cliente 1. En el nodo cliente se invoca un procedimiento remoto como si se tratara de una llamada a procedimiento local. Esta llamada se traduce en una llamada al representante del cliente. 2. El representante del cliente empaqueta todos los datos de la llamada (nombre del procedimiento y par´metros) usando un determinado formato para formar el cuerpo del mensaje a enviar (es muy usual a utilizar el proticolo XDR, eXternal Data Representation). Este proceso se suele denominar marshalling o serializaci´n. o 3. El representante el cliente env´ el mensaje con la petici´n de servicio al nodo servidor usando el ıa o m´dulo de comunicaci´n del sistema operativo. o o 4. El programa del cliente se quedar´ bloqueado esperando la respuesta. a creado October 4, 2013- p´gina 119 / 222 a
  • 120. SCD (13-14). Tema 3. Sistemas basados en paso de mensajes.. Esquema general de una RPC. Pasos en el nodo servidor y recepci´n de resultados en cliente o 1. En el nodo servidor, el sistema operativo desbloquea al proceso servidor para que se haga cargo de la petici´n y el mensaje es pasado al representante del servidor. o 2. El representante del servidor desempaqueta (unmarshalling) los datos del mensaje de petici´n (ideno tificaci´n del procedimiento y par´metros) y ejecuta una llamada al procedimiento local identificado o a usando los par´metros obtenidos del mensaje. a 3. Una vez finalizada la llamada, el representante del servidor empaqueta los resultados en un mensaje y lo env´ al cliente. ıa 4. El sistema operativo del nodo cliente desbloquea al proceso que hizo la llamada para recibir el resultado que es pasado al representante del cliente. 5. El representante del cliente desempaqueta el mensaje y pasa los resultados al invocador del procedimiento. Representaci´n de datos y paso de par´metros en la RPC o a • Representaci´n de los datos o ◾ En un sistema distribuido los nodos pueden tener diferente hardware y/o sistema operativo (sistema heterog´neo), utilizando diferentes formatos para representar los datos. e ◾ En estos casos los mensajes se env´ usando una representaci´n intermedia y los representantes ıan o de cliente y servidor se encargan de las conversiones necesarias. • Paso de par´metros En RPC, los par´metros de la llamada se pueden pasar: a a ◾ por valor: en este caso basta con enviar al representante del servidor los datos aportados por el cliente. 4.3.4 ◾ por referencia: En este caso se pasa un puntero, por lo que se han de transferir tambi´n los e datos referenciados al servidor. Adem´s, en este caso, cuando el procedimiento remoto finaliza, el a representante del servidor debe enviar al cliente, junto con los resultados, los par´metros pasados a por referencia que han sido modificados. Java Remote Method Invocation (RMI) El modelo de objetos distribuidos • Invocaci´n de m´todos en progr. orientada a objetos o e ◾ En programaci´n orientada a objetos, los objetos se comunican entre s´ mediante invocaci´n a o ı o m´todos. e ◾ Para invocar el m´todo de un objeto hay que dar una referencia del objeto, el m´todo concreto y e e los argumentos de la llamada. ◾ La interfaz de un objeto define sus m´todos, argumentos, tipos de valores devueltos y excepciones. e creado October 4, 2013- p´gina 120 / 222 a
  • 121. SCD (13-14). Tema 3. Sistemas basados en paso de mensajes.. • Invocaci´n de m´todos remotos o e ◾ En un entorno distribuido, un objeto podr´ invocar m´todos de un objeto localizado en un nodo o ıa e proceso diferente del sistema (objeto remoto) siguiendo el paradigma cliente-servidor como ocurre en RPC. ◾ Un objeto remoto podr´ recibir invocaciones locales o remotas. Para invocar m´todos de un ıa e objeto remoto, el objeto que invoca debe disponer de la referencia del objeto remoto del nodo receptor, que es unica en el sistema distribuido. ´ El modelo de objetos distribuidos. Interfaz remota y representantes • Interfaz remota: especifica los m´todos del objeto remoto que est´n accesibles para los dem´s objetos e a a as´ como las excepciones derivadas (p.e., que el servidor tarde mucho en responder). ı • Remote Method Invocation (RMI): acci´n de invocar un m´todo de la interfaz remota de un objeto o e remoto. La invocaci´n de un m´todo en una interfaz remota sigue la misma sintaxis que un objeto local. o e El modelo de objetos distribuidos. Interfaz remota y representantes • El esquema de RMI es similar a la RPC: ◾ En el cliente: un representante local de la clase del objeto receptor (stub) implementa el marshalling y la comunicaci´n con el servidor, compartiendo la misma interfaz que el objeto receptor. o ◾ En el servidor: la implementaci´n de la clase del objeto receptor (skeleton) recibe y traduce las o peticiones del stub, las env´ al objeto que implementa la interfaz remota y espera resultados ıa para formatearlos y envi´rselos al stub del cliente. a creado October 4, 2013- p´gina 121 / 222 a
  • 122. SCD (13-14). Tema 3. Sistemas basados en paso de mensajes.. El modelo de objetos distribuidos. Referencias remotas • Los stubs se generan a partir de la definici´n de la interfaz remota. o • Los objetos remotos residen en el nodo servidor y son gestionados por el mismo. • Los procesos clientes manejan referencias remotas a esos objetos. ◾ Obtienen una referencia un´ ıvoca con la localizaci´n del objeto remoto dentro del sistema diso tribuido (direcci´n IP, puerto de escucha e identificador). o • El contenido de la referencia remota no es directamente accesible, sino que es gestionado por el stub y por el enlazador. • Enlazador: servicio de un sistema distribuido que registra las asignaciones de nombres a referencias remotas. Mantiene una tabla con pares (nombre, referencia remota). ◾ En el cliente, se usa para obtener la referencia de un objeto remoto a partir de su nombre (lookup()). ◾ En el servidor, se usa para registrar o ligar (bind()) sus objetos remotos por nombre de forma que los clientes pueden buscarlos. Java RMI • Mecanismo que ofrece Java (desde JDK 1.1) para invocar m´todos de objetos remotos en diferentes e JVMs. • Permite que un programa Java exporte un objeto para que est´ disponible en la red, esperando conexe iones desde objetos ejecut´ndose en otras m´quinas virtuales Java (JVM). a a • La idea es permitir la programaci´n de aplicaciones distribuidas de forma integrada en Java como si o se tratara de aplicaciones locales, preservando la mayor parte de la sem´ntica de objetos en Java. a • Permite mantener seguro el entorno de la plataforma Java mediante gestores de seguridad y cargadores de clases. creado October 4, 2013- p´gina 122 / 222 a
  • 123. SCD (13-14). Tema 3. Sistemas basados en paso de mensajes.. Particularidades de Java RMI • Las interfaces remotas se definen como cualquier interfaz Java pero deben extender una interfaz denominada Remote y lanzar excepciones remotas para actuar como tales. • En una llamada remota, los par´metros de un m´todo son todos de entrada y la salida es el resultado a e de la llamada. ◾ Los par´metros que son objetos remotos se pasan por referencia. a ◾ Los par´metros que son objetos locales (argumentos no remotos) y los resultados se pasan por a valor (las referencias solo tienen sentido dentro de la misma JVM). ◾ Cuando el servidor no tiene la implementaci´n de un objeto local, la JVM se encarga de descargar o la clase asociada a dicho objeto. • En Java RMI, el enlazador se denomina rmiregistry. Arquitectura de Java RMI • Generalmente las aplicaciones RMI constan de servidor y clientes. • El sistema RMI proporciona los mecanismos para que el servidor y los clientes se comuniquen e intercambien informaci´n. o Arquitectura de Java RMI. Nivel de aplicaci´n o Nivel de Aplicaci´n: Los clientes y el servidor implementan la funcionalidad de la aplicaci´n RMI: o o • Servidor: ◾ Crea objetos remotos. creado October 4, 2013- p´gina 123 / 222 a
  • 124. SCD (13-14). Tema 3. Sistemas basados en paso de mensajes.. ◾ Hace accesible las referencias a dichos objetos remotos. Para ello, se registran los objetos remotos en el rmiregistry. ◾ Se mantiene activo esperando la invocaci´n de m˜etodos sobre dichos objetos remotos por parte o n de los clientes. • Clientes: ◾ Deben declarar objetos de la interfaz remota. ◾ Deben obtener referencias a objetos remotos (stubs) en el servidor. ◾ Invocan los m´todos remotos (usando el stub). e Este tipo de aplicaciones se suelen denominar Aplicaciones de objetos distribuidos Arquitectura de Java RMI. Nivel de aplicaci´n(2) o Las aplicaciones de objetos distribuidos requieren: • Localizar objetos remotos: ◾ Para ello, las aplicaciones pueden registrar sus objetos remotos utilizando el servicio rmiregistry, o puede enviar y devolver referencias a objetos remotos como argumentos y resultados. • Comunicarse con objetos remotos: • Cargar bytecodes de objetos que se pasan como par´metros o valores de retorno. a Arquitectura de Java RMI. Sistema RMI • Nivel de stubs ◾ El papel del Skeleton lo hace la plataforma RMI (a partir de JDK 1.2). ◾ El stub se genera autom´ticamente bajo demanda en tiempo de ejecuci´n (a partir de JDK 1.5, a o antes se usaba un compilador). ◾ El stub tiene la misma interfaz que el objeto remoto y conoce su localizaci´n. Realiza todo el o marshalling necesario para la llamada remota. creado October 4, 2013- p´gina 124 / 222 a
  • 125. SCD (13-14). Tema 3. Sistemas basados en paso de mensajes.. ◾ Debe haber un stub por cada instancia de una interfaz remota. • Nivel de referencias: Se encarga de: ◾ Interpretar las referencias remotas que manejan los stubs para permitirles acceder a los m´todos e correspondientes de los objetos remotos ◾ Enviar y recibir los paquetes (resultantes del marshalling de las peticiones/respuestas) usando los servicios del nivel de transporte. • Nivel de transporte: Se encarga de conectar las diferentes JVMs en el sistema distribuido. Se basa en el protocolo de red TCP/IP. Pasos para implementar una aplicaci´n Java RMI o Suponiendo, por simplicidad, que el cliente usa un unico objeto remoto, los pasos ser´ ´ ıan: 1. Crear la interfaz remota 2. Implementar el objeto remoto 3. Implementar los programas clientes 1. Crear la Interfaz remota • La interfaz remota declara los m´todos que pueden invocar remotamente los clientes. e • Deben extender la interfaz Remote del paquete java.rmi. • Los m´todos definidos deben poder lanzar una excepci´n remota. e o Ejemplo: Interfaz de un contador remoto Contador I.java § import java.rmi.Remote; import java.rmi.RemoteException; public interface Contador_I extends Remote { public void incrementa(int valor) throws RemoteException; public int getvalor() throws RemoteException; } ¦ 2. Implementar el objeto remoto • Inicialmente se deben de definir los m´todos de la interfaz remota: e Ejemplo: Clase para contador remoto Contador.java creado October 4, 2013- p´gina 125 / 222 a ¤ ¥
  • 126. SCD (13-14). Tema 3. Sistemas basados en paso de mensajes.. § import java.rmi.*; import java.rmi.server.*; ¤ public class Contador implements Contador_I{ private int valor; public Contador() throws RemoteException { valor=0; } public void incrementa(int valor) throws RemoteException { this.valor+=valor; } public int getvalor() throws RemoteException { return valor; } ...} ¦ ¥ 2. Implementar el objeto remoto(2) Una vez definidos los m´todos de la interfaz, se debe crear el objeto remoto que implementa la interfaz e remota y exportarlo al entorno RMI para habilitar la recepci´n de invocaciones remotas. Eso implica: o 1. Crear e instalar un gestor de seguridad (security manager). 2. Crear y exportar el objeto remoto. 3. Se ha de registrar la referencia a dicho objeto remoto (el stub) en el servidor de nombre (rmiregistry) asoci´ndole un nombre. Esto se hace con rebind(nombre, referencia). a Estos pasos se podr´ incluir en el programa ppal de la clase que implementa la interfaz remota (como en ıan el siguiente ejemplo) o en cualquier otro m´todo de otra clase. e 2. Implementar el objeto remoto(3) Ejemplo: m´todo main para contador remoto Contador.java e § ... public static void main(String[] args) { // Instalacion del gestor de seguridad if (System.getSecurityManager() == null) { System.setSecurityManager(new SecurityManager()); } try { String nombre = "contador"; Creacion de una instancia de la clase Contador_I cont = new Contador(); La exportamos y le damos nombre en el RMI registry creado October 4, 2013- p´gina 126 / 222 a ¤
  • 127. SCD (13-14). Tema 3. Sistemas basados en paso de mensajes.. Contador_I stub =(Contador_I) UnicastRemoteObject.exportObject(cont, 0); Registry registry = LocateRegistry.getRegistry(); registry.rebind(nombre,stub); System.out.println("Contador ligado"); } catch (Exception e) { System.err.println("Contador exception:"); e.printStackTrace(); } ¦ } ¥ 3. Implementar los programas clientes Implementar los programas clientes • El cliente tambi´n debe instalar un gestor de seguridad para que el stub local pueda descargar la e definici´n de una clase desde el servidor. o • El programa cliente deber´ obtener la referencia del objeto remoto, consultando el servicio de enlazador, a rmiregistry, en la m´quina del servidor, usando lookup(...). a • Una vez obtenida la referencia remota, el programa interact´a con el objeto remoto invocando m´todos u e del stub usando los argumentos adecuados (como si fuera local). 3. Implementar los programas clientes (2) Ejemplo: Programa cliente del contador remoto Cliente.java § import java.rmi.*; ¤ public class Cliente { public static void main(String args[]) { if (System.getSecurityManager() == null) { System.setSecurityManager(new SecurityManager()); } try { // Obteniendo una referencia a RMI registry en nodo servidor // El primer argumento del programa debe ser el nodo servidor Registry registry = LocateRegistry.getRegistry(args[0]); //Se invoca lookup en el registry para buscar objeto remoto // mediante el nombre usado en la clase Contador Contador_I cont = (Contador_I)(registry.lookup("contador"); cont.incrementa(2); System.out.println("VALOR="+cont.getvalor()); } catch (Exception e) { System.err.println("Contador_I exception:"); e.printStackTrace(); } } } ¦ creado October 4, 2013- p´gina 127 / 222 a ¥
  • 128. SCD (13-14). Tema 3. Sistemas basados en paso de mensajes.. Bibliograf´ del tema 3. ıa Para m´s informaci´n, ejercicios, bibliograf´ adicional, se puede consultar: a o ıa 3.1. Mecanismos b´sicos en sistemas basados en paso de mensajes. Palma (2003), cap´ a ıtulos 7,8,9. Almeida (2008), cap´ ıtulo 3. Kumar (2003), cap´ ıtulo 6. 3.2. Paradigmas de interacci´n de procesos en programas distribuidos Andrews (2000), cap´ o ıtulo 9. Almeida (2008), cap´ ıtulos 5,6. 3.3. Mecanismos de alto nivel en sistemas distribuidos. RPC y RMI. Palma (2003), cap´ ıtulo 10. Coulouris (2011), cap´ ıtulo 5. 4.4 32 Problemas del tema 3. En un sistema distribuido, 6 procesos clientes necesitan sincronizarse de forma espec´ ıfica para realizar cierta tarea, de forma que dicha tarea s´lo podr´ ser realizada cuando tres procesos est´n preparados para o a e realizarla. Para ello, env´ peticiones a un proceso controlador del recurso y esperan respuesta para poder ıan realizar la tarea espec´ ıfica. El proceso controlador se encarga de asegurar la sincronizaci´n adecuada. Para o ello, recibe y cuenta las peticiones que le llegan de los procesos, las dos primeras no son respondidas y producen la suspensi´n del proceso que env´ la petici´n (debido a que se bloquea esperando respuesta) o ıa o pero la tercera petici´n produce el desbloqueo de los tres procesos pendientes de respuesta. A continuaci´n, o o una vez desbloqueados los tres procesos que han pedido (al recibir respuesta), inicializa la cuenta y procede c´ ıclicamente de la misma forma sobre otras peticiones. El c´digo de los procesos clientes es el siguiente, asumiendo que se usan operaciones s´ o ıncronas. § process Cliente[ i : 0..5 ] ; begin while true do begin send( peticion, Controlador ); receive( permiso, Controlador ); Realiza_tarea_grupal( ); end end ¦ ¤§ process Controlador ; begin while true do begin ... end end ¥¦ ¥ Describir en pseudoc´digo el comportamiento del proceso controlador, utilizando una orden de espera seleco tiva que permita implementar la sincronizaci´n requerida entre los procesos. Es posible utilizar una sentencia o del tipo select for i=... to ... para especificar diferentes ramas de una sentencia selectiva que comparten el mismo c´digo dependiente del valor de un ´ o ındice i. 33 ¤ En un sistema distribuido, 3 procesos productores producen continuamente valores enteros y los env´ a un ıan creado October 4, 2013- p´gina 128 / 222 a
  • 129. SCD (13-14). Tema 3. Sistemas basados en paso de mensajes.. proceso buffer que los almacena temporalmente en un array local de 4 celdas enteras para ir envi´ndoselos a a un proceso consumidor. A su vez, el proceso buffer realiza lo siguiente, sirviendo de forma equitativa al resto de procesos: a) Env´ enteros al proceso consumidor siempre que su array local tenga al menos dos elementos ıa disponibles. b) Acepta env´ de los productores mientras el array no est´ lleno, pero no acepta que cualquier productor ıos e pueda escribir dos veces consecutivas en el b´fer. u El c´digo de los procesos productor y consumidor es el siguiente, asumiendo que se usan operaciones o s´ ıncronas. § { Proceso Productor(i ), i=0,1,2 } while true do begin Produce(&dato ); send( &dato, Buffer ); end ¦ ¤ § { Proceso Consumidor } while true do begin receive ( &dato, Buffer ); Consume (dato); end ¥ ¦ Describir en pseudoc´digo el comportamiento del proceso Buffer, utilizando una orden de espera selectiva o que permita implementar la sincronizaci´n requerida entre los procesos. o § { Proceso Buffer } while true do begin ... end ¦ ¤ ¥ ¤ ¥ 34 Suponer un proceso productor y 3 procesos consumidores que comparten un buffer acotado de tama˜o B. n Cada elemento depositado por el proceso productor debe ser retirado por todos los 3 procesos consumidores para ser eliminado del buffer. Cada consumidor retirar´ los datos del buffer en el mismo orden en el que son a depositados, aunque los diferentes consumidores pueden ir retirando los elementos a ritmo diferente unos de otros. Por ejemplo, mientras un consumidor ha retirado los elementos 1, 2 y 3, otro consumidor puede haber retirado solamente el elemento 1. De esta forma, el consumidor m´s r´pido podr´ retirar hasta B elementos a a ıa m´s que el consumidor m´s lento. a a Describir en pseudoc´digo el comportamiento de un proceso que implemente el buffer de acuerdo con el o esquema de interacci´n descrito usando una construcci´n de espera selectiva, as´ como el del proceso o o ı productor y de los procesos consumidores. Comenzar identificando qu´ informaci´n es necesario representar, e o para despu´s resolver las cuestiones de sincronizaci´n. Una posible implementaci´n del bufffer mantendr´ e o o ıa, para cada proceso consumidor, el puntero de salida y el n´mero de elementos que quedan en el buffer por u consumir (ver figura). creado October 4, 2013- p´gina 129 / 222 a
  • 130. SCD (13-14). Tema 3. Sistemas basados en paso de mensajes.. 35 Una tribu de antrop´fagos comparte una olla en la que caben M misioneros. Cuando alg´n salvaje quiere o u comer, se sirve directamente de la olla, a no ser que ´sta est´ vac´ Si la olla est´ vac´ el salvaje despertar´ e e ıa. a ıa, a al cocinero y esperar´ a que ´ste haya rellenado la olla con otros M misioneros. a e Proceso Salvaje(i), i=0,1,2 : § while true do begin Servirse_1_misionero(); Comer(); end ¦ Proceso Cocinero : ¤ § while true do begin Dormir(); Rellenar_Olla(); end ¥ ¦ ¤ ¥ Implementar los procesos salvajes y cocinero usando paso de mensajes, usando un proceso olla que incluye una construcci´n de espera selectiva que sirve peticiones de los salvajes y el cocinero para mantener la o sincronizaci´n requerida, teniendo en cuenta que: o • La soluci´n no debe producir interbloqueo. o • Los salvajes podr´n comer siempre que haya comida en la olla, a • Solamente se despertar´ al cocinero cuando la olla est´ vac´ a e ıa. • Lois procesos usan operaciones de comunicaci´n s´ o ıncronas. 36 Considerar un conjunto de N procesos, P(i), i = 0, ..., N − 1 conectados en forma de anillo. Cada proceso tiene un valor local almacenado en su variable local mi valor. Deseamos calcular la suma de los valores locales almacenados por los procesos de acuerdo con el algoritmo que se expone a continuaci´n. o creado October 4, 2013- p´gina 130 / 222 a
  • 131. SCD (13-14). Tema 3. Sistemas basados en paso de mensajes.. Los procesos realizan una serie de iteraciones para hacer circular sus valores locales por el anillo. En la primera iteraci´n, cada proceso env´ su valor local al siguiente proceso del anillo, al mismo tiempo que o ıa recibe del proceso anterior el valor local de ´ste. A continuaci´n acumula la suma de su valor local y el e o recibido desde el proceso anterior. En las siguientes iteraciones, cada proceso env´ al siguiente proceso ıa siguiente el valor recibido en la anterior iteraci´n, al mismo tiempo que recibe del proceso anterior un nuevo o valor. Despu´s acumula la suma. Tras un total de N − 1 iteraciones, cada proceso conocer´ la suma de todos e a los valores locales de los procesos. Dar una descripci´n en pseudoc´digo de los procesos siguiendo un estilo SPMD y usando operaciones de o o env´ y recepci´n s´ ıo o ıncronas. § { Proceso P[i ], i =0,..., N−1 } var mi_valor : integer := ... ; suma : integer ; begin for j := 0 hasta N-1 do begin ... end end ¦ ¤ ¥ 37 Considerar un estanco en el que hay tres fumadores y un estanquero. Cada fumador continuamente l´ un ıa cigarro y se lo fuma. Para liar un cigarro, el fumador necesita tres ingredientes: tabaco, papel y cerillas. Uno de los fumadores tiene solamente papel, otro tiene solamente tabaco, y el otro tiene solamente cerillas. El estanquero tiene una cantidad infinita de los tres ingredientes. creado October 4, 2013- p´gina 131 / 222 a
  • 132. SCD (13-14). Tema 4. Introducci´n a los sistemas de tiempo real.. o • El estanquero coloca aleatoriamente dos ingredientes diferentes de los tres que se necesitan para hacer un cigarro, desbloquea al fumador que tiene el tercer ingrediente y despu´s se bloquea. El fumador e seleccionado, se puede obtener f´cilmente mediante una funci´n int Genera ingrediente() que a o devuelve el ´ ındice (0,1, ´ 2) del fumador escogido. o • El fumador desbloqueado toma los dos ingredientes del mostrador, desbloqueando al estanquero, l´ ıa un cigarro y fuma durante un tiempo. • El estanquero, una vez desbloqueado, vuelve a poner dos ingredientes aleatorios en el mostrador, y se repite el ciclo. Describir una soluci´n distribuida que use env´ as´ o ıo ıncrono seguro y recepci´n s´ o ıncrona, para este problema usando un proceso Estanquero y tres procesos fumadores (Fumador(i), i=0,1,2). Proceso Estanquero : § while true do begin .... end ¦ Proceso Fumador(i), i=0,1,2 : ¤ § while true do begin .... end ¥ ¦ ¤ ¥ creado October 4, 2013- p´gina 132 / 222 a
  • 133. Chapter 5 Tema 4. Introducci´n a los sistemas de o tiempo real. 5.1 5.1.1 Concepto de sistema de tiempo real. Medidas de tiempo y modelo de tareas. Definici´n, tipos y ejemplos o Sistemas de Tiempo Real • Constituyen un tipo de sistema en el que la ejecuci´n del sistema se debe producir dentro de unos o plazos de tiempo predefinidos para que funcione con la suficiente garant´ ıa. • En un sistema adem´s concurrente ser´ necesario que todos los procesos sobre un procesador o sobre a a varios se ejecuten en los plazos de tiempo predefinidos. Definici´n de un Sistema de Tiempo Real o Stankovic (1997) da la siguiente definici´n: o Un sistema de tiempo real es aquel sistema cuyo funcionamiento correcto depende no s´lo o de resultados l´gicos producidos por el mismo, sino tambi´n del instante de tiempo en el que o e se producen esos resultados Correcci´n Funcional + Correcci´n Temporal o o El no cumplimiento de una restricci´n temporal lleva a un fallo del sistema o 133
  • 134. SCD (13-14). Tema 4. Introducci´n a los sistemas de tiempo real.. o Ejemplo: Sistema de Control • Objetivo: Ejecutar el lazo de control del sistema en instantes de tiempo prefijados. • Condici´n de tiempo real: no puede haber retrasos en la ejecuci´n del lazo de control, ya que afecta o o al rendimiento y provoca perdida de estabilidad. Consignas SISTEMA DE CONTROL Medidas Visualización datos Acciones SISTEMA CONTROLADO ENTORNO FÍSICO Los sistemas de control (no necesariamente computadores sino sistemas el´ctricos, mec´nicos, ´pticos) suelen e a o realizar la acci´n de correcci´n para el control del sistema en un lazo (bucle) con el objeto de mantener o o o establecer una condiciones en el sistema controlado. En la actualidad los sistemas de control se est´n a “digitalizando”, es decir, sustituyendo por sistemas de control computerizados. La estructura general de una aplicaci´n de control incluye: o • Sistema de control: que se encarga de monitorizar el sistema controlado, y si se produce una desviaci´n o respecto del comportamiento esperado se activan las se˜ales de control (acciones) especificas para n disminuir esa desviaci´n. o • Sensores: dispositivos de naturaleza electr´magn´tica, mec´nica u ´ptica que obtienen el estado del o e a o entorno f´ ısico a partir de la cuantificaci´n de alguna variable f´ o ısica. Los sensores se encargan de realizar la transducci´n entre valores en alguna variable f´ o ısica y la valores de tensi´n (los que se o utilizan desde cualquier medio computerizado). Ejemplos: sensores de temperatura, sensores de presencia, de luminosidad, tac´metros, . . . o • Actuadores: dispositivos de naturaleza electromagn´tica, mec´nica u ´ptica que realizan acciones e a o concretas en el entorno f´ ısico a partir de las se˜ales de control enviadas por el sistema de control. La n traducci´n pasa valores de tensi´n en acciones concretas. o o Ejemplos: motores, lamparas, valvulas, . . . • Sistema Controlado: es el sistema f´ ısico del que queremos controlar su comportamiento. • Consignas: son las ordenes que realizan los usuarios para establecer el sistema controlado en un valor de referencia. creado October 4, 2013- p´gina 134 / 222 a
  • 135. SCD (13-14). Tema 4. Introducci´n a los sistemas de tiempo real.. o • Visualizaci´n de datos: se obtienen los datos para que el operador pueda visualizarlos. o ¿Qu´ tipo de sistema de tiempo real es un sistema de control? Depende del tipo de actividad, pero para e actividades de control deber´ ser de tipo estricto. ıa Tipos de Sistemas de Tiempo Real Habitualmente suele asociarse la denominaci´n de sistemas de tiempo real a los siguientes tipos de sistemas: o • Sistema “en-l´ ınea”: Siempre est´ disponible, pero no se garantiza una respuesta en intervalo de a tiempo acotado. ◾ Ejemplos: Cajeros autom´ticos, sistemas de reservas de vuelo. a • Sistema interactivo: El sistema ofrece una respuesta en un tiempo, aunque no importa el tiempo que necesita para su ejecuci´n. o ◾ Ejemplos: Reproductor DVD, sistema aire acondicionado, juegos, .. • Sistema de respuesta r´pida: El sistema ofrece una respuesta en el menor tiempo posible y de forma a inmediata. ◾ Ejemplos: Sistema anti incendios, alarmas, etc. Tipos de Sistemas de Tiempo Real Sistema de respuesta rápida Sistema En-línea STR Sistema interactivo creado October 4, 2013- p´gina 135 / 222 a
  • 136. SCD (13-14). Tema 4. Introducci´n a los sistemas de tiempo real.. o Ejemplos de Sistemas de Tiempo Real En la actualidad hay muchos ejemplos de uso de Sistemas de Tiempo Real, podemos citar algunos de ellos: • Automoci´n: sistema de ignici´n, transmisi´n, direcci´n asistida, frenos antibloqueo (ABS), control de o o o o la tracci´n, ... o • Electrodom´sticos: televisores, lavadoras, hornos de microondas, reproductores de videos o DVDs, e sistemas de seguridad y vigilancia, ... • Aplicaciones aeroespaciales: control de vuelos, controladores de motores, pilotos autom´ticos, ... a • Equipamiento m´dico: como sistemas de monitorizaci´n de anestesia, monitores ECG, e o • Sistemas de defensa: como sistemas radar de aviones, sistemas de radio, control de misiles, ... 5.1.2 Propiedades de los Sistemas de Tiempo Real Propiedades de un STR Al depender la correcci´n del sistema de las restricciones temporales, los sistemas de tiempo real tienen que o cumplir una serie de propiedades: • Reactividad. • Predecibilidad. • Confiabilidad. a continuaci´n veremos cada una de estas propiedades con m´s detalle. o a Propiedad: Reactividad El sistema tiene que interaccionar con el entorno, y responder de la manera esperada a los est´ ımulos externos dentro de un intervalo de tiempo previamente definido. creado October 4, 2013- p´gina 136 / 222 a
  • 137. SCD (13-14). Tema 4. Introducci´n a los sistemas de tiempo real.. o Propiedad: Predecibilidad Tener un comportamiento predecible implica que la ejecuci´n del sistema tiene que ser determinista, y por o lo tanto, se debe garantizar su ejecuci´n dentro del plazo de tiempo definido. o • Las respuestas han de producirse dentro de las restricciones temporales impuestas por el entorno (sistema controlado), y que suele ser diferente para cada proceso del sistema. • Es necesario conocer el comportamiento temporal de los componentes software (SO, middleware, librer´ etc) y hardware utilizados, as´ como del lenguaje de programaci´n. ıa, ı o • Si no se puede tener un conocimiento temporal exacto, hay que definir marcos de tiempo acotados; p.e. conocer el tiempo de peor ejecuci´n de un algoritmo, el tiempo m´ximo de acceso a un dato de E/S) o a Propiedad: Confiabilidad • La Confiabilidad (Dependability) mide el grado de confianza que se tiene del sistema. Depende de: ◾ Disponibilidad (avalaibility). Capacidad de proporcionar servicios siempre que se solicita. ◾ Robustez o tolerancia a fallos (fault tolerant). Capacidad de operar en situaciones excepcionales sin poseer un comportamiento catastr´fico. o ◾ Fiabilidad (reliability). Capacidad de ofrecer siempre los mismos resultados bajo las mismas condiciones. ◾ Seguridad: Capacidad de protegerse ante ataques o fallos accidentales o deliberados (safety), y a la no vulnerabilidad de los datos (security). • Cuando esta propiedad es cr´ ıtica (su no cumplimiento lleva a p´rdida humana o econ´mica), el sistema e o se denomina sistema de tiempo real cr´ ıtico (safety-critical system) ◾ Ejemplos: Sistemas de Avi´nica, Sistemas de automoci´n, Centrales nucleares, etc. o o creado October 4, 2013- p´gina 137 / 222 a
  • 138. SCD (13-14). Tema 4. Introducci´n a los sistemas de tiempo real.. o Tipos de STRs (otra clasif. distinta) Tipo No permisivos o estrictos (hard) Permisivos, flexibles o no estrictos (soft) Firmes Caracter´ ısticas Plazo de respuesta dentro del l´ ımite preestablecido. Aunque el plazo de respuesta es importante, el sistema funciona correctamente aunque no respondan en el plazo de tiempo fijado Se permiten algunos fallos en el plazo de respuesta, pero un n´mero u excesivo provoca una fallo completo del sistema Ejemplos Control de vuelo de una aeronave. Sistema autom´tico de frenado a ABS. Sistema de adquisici´n de datos o meteorol´gicos. o Sistema de control de reserva de vuelos. Sistema de video bajo demanda. Los sistemas de tiempo real pueden tener componentes de las tres clases. Imagen obtenida de: http://www.embedded.com/electronics-blogs/beginner-s-corner/4023859/Introduction-to-Real-Time 5.1.3 Modelo de Tareas Modelo de Tareas • Un sistema de tiempo real se estructura en tareas que acceden a los recursos del sistema. creado October 4, 2013- p´gina 138 / 222 a
  • 139. SCD (13-14). Tema 4. Introducci´n a los sistemas de tiempo real.. o Tarea 1 Tarea 2 Tarea 3 Tarea 4 codigo codigo codigo codigo restricciones temporales restricciones temporales restricciones temporales restricciones temporales Memoria CPU Recurso 1 Recurso 2 Recurso 3 Tareas y recursos. Definici´n. o En los STR cabe distinguir estos dos tipos de elementos: • Tarea: El conjunto de acciones que describe el comportamiento del sistema o parte de ´l en base a la e ejecuci´n secuencial de una secci´n de c´digo (o programa). Equivalente al proceso o hebra. o o o ◾ La tarea satisface una necesidad funcional concreta. ◾ La tarea tiene definida unas restricciones temporales a partir de los Atributos Temporales. • Recursos: Elementos disponibles para la ejecuci´n de las tareas. o ◾ Recursos Activos: Procesador, Red, ... ◾ Recursos Pasivos: Datos, Memoria, Dispositivos de E/S, ... Atributos temporales • Tiempo de computo o de ejecuci´n (C): Tiempo necesario para la ejecuci´n de la tarea. o o • Tiempo de respuesta (R): Tiempo que ha necesitado el proceso para completarse totalmente. • Plazo de respuesta m´xima (deadline) (D): Define el m´ximo tiempo de respuesta posible. a a • Periodo (T): Intervalo de tiempo entre dos activaciones sucesivas en el caso de una tarea peri´dica. o creado October 4, 2013- p´gina 139 / 222 a
  • 140. SCD (13-14). Tema 4. Introducci´n a los sistemas de tiempo real.. o Activación i Activación (i+1) Tiempo de computo ( C) C = C1 + C2 Tiempo de respuesta (R) Plazo de respuesta máxima (D) Periodo (T) Tipos de Tareas • Peri´dica: T es el per´ o ıodo de activaci´n de la tarea. o T T T t D D D fallo • Aperi´dica: o t D D • Espor´dica: T es la separaci´n m´ a o ınima entre eventos. T T t D D creado October 4, 2013- p´gina 140 / 222 a
  • 141. SCD (13-14). Tema 4. Introducci´n a los sistemas de tiempo real.. o Planificaci´n de Tareas o • La planificaci´n de tareas consiste en asignar las tareas a los recursos activos de un sistema (princio palmente el procesador o procesadores) para garantizar la ejecuci´n de todas las tareas de acuerdo a o un conjunto de restricciones especificas. ◾ En tareas de tiempo real las restricciones suelen estar asociadas a restricciones temporales como los plazos l´ ımites. Tarea 1 Tarea 2 Tarea 3 Tarea 4 CORE 1 t CORE 2 t Dise˜o de la planificaci´n de tareas. n o El problema de la planificaci´n supone: o • Determinar los procesadores disponibles a los que se puede asociar las tareas. • Determinar las relaciones de dependencias de las tareas: ◾ Relaciones de precedencia que hay entre las distintas tareas. ◾ Determinar los recursos comunes a los que acceden las distintas tareas. • Determinar el orden de ejecuci´n de la tareas para garantizar las restricciones especificadas. o Esquema de planificaci´n de tareas o Para determinar la planificabilidad de un conjunto de tareas se requiere un esquema de planificaci´n que o cubra los dos siguientes aspectos: • Un algoritmo de planificaci´n, que define un criterio (pol´ o ıtica de planificaci´n) que determina el orden o de acceso de las tareas a los distintos procesadores. • Un m´todo de an´lisis (test de planificabilidad) que permite predecir el comportamiento temporal del e a sistema, y determina si la planificabilidad es factible bajo las condiciones o restricciones especificadas creado October 4, 2013- p´gina 141 / 222 a
  • 142. SCD (13-14). Tema 4. Introducci´n a los sistemas de tiempo real.. o ◾ Se pueden comprobar si los requisitos temporales est´n garantizados en todos los casos posibles. a ◾ En general se estudia el peor comportamiento posible, es decir, con el WCET (Worst Case Execution Time). C´lculo del WCET. a • Todos los m´todos de planificaci´n parte de que se conoce el WCET (C), el tiempo de peor ejecuci´n e o o de cada tarea. • ¿ C´mo podemos calcular el valor de C para cada tarea ? o • Hay dos formas de obtenerlo: ◾ Medida directa del tiempo de ejecuci´n (en el peor caso) en la plataforma de ejecuci´n. o o ▸ Se realizan m´ltiples experimentos, y se hace una estad´ u ıstica. ◾ An´lisis del c´digo ejecutable a o ▸ Se descompone el c´digo en un grafo de bloques secuenciales. o ▸ Se calcula el tiempo de ejecuci´n de cada bloque. o ▸ Se busca el camino m´s largo. a Restricciones temporales Para determinar la planificaci´n del sistema necesitamos conocer las restricciones temporales de cada tarea o del sistema. Aqu´ vemos dos ejemplos de restricciones temporales: ı • C = 2 ms, T = D = 10 ms. Es una tarea peri´dica que se activa cada 10 ms, y se ejecuta en un tiempo o m´ximo de 2 ms en el peor de los casos. a • C = 10 ms, T = 100 ms; D = 90 ms. Es una tarea peri´dica que se activa cada 100 ms, se ejecuta en o cada activaci´n un m´ximo de 10 ms, y desde que se inicia la activaci´n hasta que concluye no puede o a o pasar m´s de 90 ms. a 5.2 Esquemas de planificaci´n o Tipos de Esquemas de Planificaci´n o Los esquemas de planificaci´n para un sistema monoprocesador son: o • Planificaci´n est´tica off-line sin prioridades o a ◾ Planificaci´n c´ o ıclica (ejecutivo c´ ıclico) • Planificaci´n basada en prioridades o ◾ Prioridades est´ticas a ▸ Prioridad al m´s frecuente (RMS, Rate Monotonic Scheduling) a creado October 4, 2013- p´gina 142 / 222 a
  • 143. SCD (13-14). Tema 4. Introducci´n a los sistemas de tiempo real.. o ▸ Prioridad al m´s urgente (DMS, Deadline Monotonic Scheduling) a ◾ Prioridades din´micas a 5.2.1 ▸ Proximidad del plazo de respuesta (EDF, Earliest Deadline First) ▸ Prioridad al de menor holgura (LLF, Least Laxity First) Planificaci´n C´ o ıclica. Planificaci´n C´ o ıclica • La planificaci´n se basa en construir un plan de ejecuci´n (plan principal) de forma explicita y fuera o o de l´ ınea (off-line) en el que se especifica el entrelazado de las tareas peri´dicas de tal forma que su o ejecuci´n c´ o ıclica garantiza el cumplimiento de los plazos de las tareas. ◾ La estructura de control o programa c´ ıclico se denomina ejecutivo c´ ıclico. • El entrelazado es fijo y se define en el plan principal que se construye antes de poner en marcha el sistema (off-line). • La duraci´n del ciclo principal es igual al hiperperiodo o ◾ TM = mcm(T1 , T2 , . . . , Tn ) ◾ se supone tiempo entero (ticks de reloj) ◾ el comportamiento temporal del sistema se repite cada ciclo principal Ejemplo de planificaci´n c´ o ıclica. Tarea A B C D E T 25 25 50 50 100 C 10 8 5 4 2 • El ciclo principal dura 100 ms TM = mcm(25, 25, 50, 50, 100) = 100 • Se compone de 4 ciclos secundarios de 25 ms cada uno. TM = 100 ms TS = 25 ms A 0 B C A 25 B D E A 50 B C A 75 B D 100 creado October 4, 2013- p´gina 143 / 222 a
  • 144. SCD (13-14). Tema 4. Introducci´n a los sistemas de tiempo real.. o Implementaci´n de la Planificaci´n C´ o o ıclica § void ejecutivo_ciclico() { int nciclos = 4 , frame = 0 ; while (true) { switch (frame) { case 0 : A; B; C; break case 1 : A; B; D; E; break case 2 : A; B; C; break case 3 : A; B; D; break } } frame = (frame+1) % nciclos; wait_until_next_clock_tick(); } // final del ejecutivo ciclico ¦ ¤ ; ; ; ; ¥ Propiedades de la Planificaci´n C´ o ıclica • No hay concurrencia en la ejecuci´n. o ◾ Cada ciclo secundario es una secuencia de llamadas a procedimientos ◾ No se necesita un n´cleo de ejecuci´n multitarea u o • Los procedimientos pueden compartir datos. ◾ No se necesitan mecanismos de exclusi´n mutua como los sem´foros o monitores o a • No hace falta analizar el comportamiento temporal. ◾ El sistema es correcto por construcci´n. o Problemas de la Planificaci´n C´ o ıclica • Dificultad para incorporar tareas con periodos largos. • Las tareas espor´dicas son dif´ a ıciles de tratar. ◾ Se puede utilizar un servidor de consulta. • El plan ciclo del proyecto es dif´ de construir. ıcil ◾ Si los periodos son de diferentes ´rdenes de magnitud el n´mero de ciclos secundarios se hace o u muy grande. ◾ Puede ser necesario partir una tarea en varios procedimientos. ◾ Es el caso m´s general de sistemas en tiempo real cr´ a ıticos. • Es poco flexible y dif´ de mantener. ıcil ◾ Cada vez que se cambia una tarea hay que rehacer toda la planificaci´n. o creado October 4, 2013- p´gina 144 / 222 a
  • 145. SCD (13-14). Tema 4. Introducci´n a los sistemas de tiempo real.. o 5.2.2 Planificaci´n con prioridades o Planificaci´n con prioridades o • La prioridad es un mecanismo elemental para planificar la ejecuci´n de un conjunto de tareas. o ◾ Es un atributo de las tareas normalmente ligado a su importancia relativa en el conjunto de tareas. ◾ Por convenci´n se asigna n´meros enteros mayores a procesos m´s urgentes. o u a ◾ La prioridad de una tarea la determina sus necesidades temporales; no es importante el rendimiento o comportamiento del sistema. • Una tarea puede estar en varios estados: • Las tareas ejecutables se despachan para su ejecuci´n en orden de o prioridad. Planificaci´n RMS o • RMS (Rate Monotonic Scheduling): Es un m´todo de planificaci´n est´tico on-line con asignaci´n e o a o de prioridades a las tareas m´s frecuentes. a • A cada tarea se le asigna una (´nica) prioridad basada en su periodo; cuanto menor sea el periodo u (mayor frecuencia) → mayor prioridad. ∀i, j Ti < Tj ⇒ Pi < Pj • Esta asignaci´n de prioridades es optima en el caso de que todas las tareas sean peri´dicas, y el o o plazo de respuesta m´xima D coincida con el periodo. a Nota: aqu´ se emplean siempre numeros enteros menores para procesos m´s urgentes o m´s prioritarios. ı a a Ejemplo de planificaci´n RMS (1) o • Dada un conjunto de tres tareas con las siguientes restricciones temporales: Tareas 1 2 3 C 10 5 9 D 30 40 50 T 40 40 50 • La aplicaci´n del m´todo de planificaci´n RMS indica que la tarea 1 es la que tiene mayor prioridad, o e o luego la 2, y luego la 3. creado October 4, 2013- p´gina 145 / 222 a
  • 146. SCD (13-14). Tema 4. Introducci´n a los sistemas de tiempo real.. o Ejemplo de planificaci´n RMS (2) o • Para analizar la planificabilidad del sistema con dichas restricciones, hay que estudiar en el cronograma que: ◾ Para cada tarea: → Ri < Ti • Solo hay que probar la ejecuci´n correcta de todas las tareas en el hiperperiodo, es decir, H = mcm(Ti). o ◾ Si se cumple en el hiperperiodo, se repetir´ indefinidamente. a 1 2 3 0 20 40 60 80 100 120 140 160 Planificaci´n EDF o • EDF (Earliest Deadline First, primero al m´s urgente): La asignaci´n de prioridad se establece una a o prioridad m´s alta a la que se encuentre m´s pr´xima a su plazo de respuesta m´xima (deadline). En a a o a caso de igualdad se hace una elecci´n no determinista de la siguiente tarea a ejecutar. o • Es un algoritmo de planificaci´n din´mica, dado que la prioridad de cada tarea cambia durante la o a evoluci´n del sistema. o • Es m´s ´ptimo porque no es necesario que las tareas sean peri´dicas. a o o • En menos pesimista que RMS. Ejemplo de planificaci´n EDF o creado October 4, 2013- p´gina 146 / 222 a
  • 147. SCD (13-14). Tema 4. Introducci´n a los sistemas de tiempo real.. o Tareas J1 J2 EDF J1 1 RMS J1 2 4 2 6 2 2 6 12 14 1 2 4 1 2 8 10 fallo 1 J2 D 5 7 1 2 1 0 T 5 7 1 J2 0 C 2 4 2 10 16 18 20 1 2 8 2 12 2 14 22 1 2 16 18 20 22 creado October 4, 2013- p´gina 147 / 222 a
  • 148. SCD (13-14). Tema 4. Introducci´n a los sistemas de tiempo real.. o creado October 4, 2013- p´gina 148 / 222 a
  • 149. Part III Seminarios y guiones de pr´cticas a 149
  • 151. Chapter 6 Seminario 1. Programaci´n multihebra y o sincronizaci´n con sem´foros. o a Introducci´n o Este seminario tiene cuatro partes, inicialmente se repasa el concepto de hebra, a continuaci´n se da una o breve introducci´n a la interfaz (posix) de las librer´ de hebras disponibles en linux. A continuaci´n, se o ıas o estudia el mecanismo de los sem´foros como herramienta para solucionar problemas de sincronizaci´n y, por a o ultimo, se hace una introducci´n a una librer´ para utilizar sem´foros con hebras posix. ´ o ıa a • El objetivo es conocer algunas llamadas b´sicas de dicho interfaz para el desarrollo de ejemplos a sencillos de sincronizaci´n con hebras usando sem´foros (pr´ctica 1) o a a • Las partes relacionadas con hebras posix est´n basadas en el texto disponible en esta web: https://computing.llnl.gov a 6.1 Concepto e Implementaciones de Hebras Procesos: estructura En un sistema operativo pueden existir muchos procesos ejecut´ndose concurrentemente, cada proceso cora responde a un programa en ejecuci´n y tiene su propio flujo de control. o • Cada proceso ocupa una zona de memoria con (al menos) estas partes: ◾ texto: zona con la secuencia de instrucciones que se est´n ejecutando. a ◾ datos: espacio (de tama˜o fijo) ocupado por variables globales. n ◾ pila: espacio (de tama˜o cambiante) ocupado por variables locales. n ◾ mem. din´mica (heap): espacio ocupado por variables din´micas. a a • Cada proceso tiene asociados (entre otros) estos datos: ◾ contador de programa (pc): dir. en memoria (zona de texto) de la siguiente instrucci´n a ejecutar. o ◾ puntero de pila (sp): dir. en memoria (zona de pila) de la ultima posici´n ocupada por la pila. ´ o 151
  • 152. SCD (13-14). Seminario 1. Programaci´n multihebra y sincronizaci´n con sem´foros.. o o a Diagrama de la estructura de los procesos Podemos visualizarla (simplificadamente) como sigue: Proceso 0 Proceso n Proceso 1 pc pc pc sp sp sp texto texto texto ...... datos pila datos datos pila pila heap heap heap Ejemplo de un proceso En el siguiente programa escrito en C/C++, el estado del proceso (durante la ejecuci´n de k=1;) es el que o se ve a la derecha: § int a,b,c ; // variables globales void subprograma1() { int i,j,k ; // vars. locales (1) k = 1 ; } void subprograma2() { float x ; // vars. locales (2) subprograma1() ; } int main() { char * p = new char ; // ”p” local *p = ’a’; // ”*p” en el heap subprograma2() ; } ¦ ¤ Proceso pc sp texto … k=1; … datos a,b,c pila p x i,j,k heap *p ¥ Procesos y hebras La gesti´n de varios procesos no independientes (cooperantes) es muy util pero consume una cantidad o ´ apreciable de recursos del SO: • Tiempo de procesamiento para repartir la CPU entre ellos creado October 4, 2013- p´gina 152 / 222 a
  • 153. SCD (13-14). Seminario 1. Programaci´n multihebra y sincronizaci´n con sem´foros.. o o a • Memoria con datos del SO relativos a cada proceso • Tiempo y memoria para comunicaciones entre esos procesos para mayor eficiencia en esta situaci´n se dise˜´ el concepto de hebra: o no • Un proceso puede contener una o varias hebras. • Una hebra es un flujo de control en el texto (com´n) del proceso al que pertencen. u • Cada hebra tiene su propia pila (vars. locales), vac´ al inicio. ıa • Las hebras de un proceso comparten la zona de datos (vars. globales), y el heap. Diagrama de la estructura de procesos y hebras Podriamos visualizarlos (simplificadamente) como sigue: Proceso 0 Proceso 1 texto texto datos datos heap heap Hebra 0 Hebra 0 Hebra 1 pc pc pc sp sp sp pila pila pila .......... ..... Inicio y finalizaci´n de hebras o Al inicio de un programa, existe una unica hebra (que ejecuta la funci´n main en C/C++). Durante la ´ o ejecuci´n del programa: o • Una hebra A en ejecuci´n puede crear otra hebra B en el mismo proceso de A. o • Para ello, A designa un subprograma f (una funci´n C/C++) del texto del proceso, y despu´s contin´a o e u su ejecuci´n. La hebra B: o ◾ ejecuta el subprograma f concurrentemente con el resto de hebras. ◾ termina normalmente cuando finaliza de ejecutar dicho subprograma creado October 4, 2013- p´gina 153 / 222 a
  • 154. SCD (13-14). Seminario 1. Programaci´n multihebra y sincronizaci´n con sem´foros.. o o a • Una hebra puede finalizar en cualquier momento (antes de terminar el subprograma con que se inici´). o • Una hebra puede finalizar otra hebra en ejecuci´n B, sin esperar que termine o • Una hebra puede esperar a que cualquier otra hebra en ejecuci´n finalice. o Ejemplo de estado de un proceso con tres hebras En main se crean dos hebras, despu´s se llega al estado que vemos: e § int a,b,c ; ¤ Proceso void subprograma1() { int i,j,k ; // ... } void subprograma2() { float x ; // ... } int main() { char * p = new char ; // cr.he.subp.2 // cr.he.subp.1 // ... } ¦ 6.2 6.2.1 texto subprograma1(){ … } subprograma2(){ … } main() { … } datos a,b,c heap *p Hebra 0 Hebra 1 Hebra 2 pc pc pc sp sp sp pila p pila x pila i,j,k ¥ Hebras POSIX Introducci´n o Introducci´n o En esta secci´n veremos algunas llamadas b´sicas de la parte de hebras de POSIX (IEEE std 1003.1), en o a la versi´n de 2004: o • El est´ndar POSIX define los par´metros y la sem´ntica de un amplio conjunto de funciones para a a a diversos servicios del SO a los programas de usuario. ◾ http://pubs.opengroup.org/onlinepubs/009695399/ • Una parte de las llamadas de POSIX est´n dedicadas a gesti´n (creaci´n, finalizaci´n, sincronizaci´n, a o o o o etc...) de hebras, son las que aparecen aqu´ ı: ◾ http://pubs.opengroup.org/onlinepubs/009695399/idx/threads.html creado October 4, 2013- p´gina 154 / 222 a
  • 155. SCD (13-14). Seminario 1. Programaci´n multihebra y sincronizaci´n con sem´foros.. o o a La librer´ NPTL ıa Los ejemplos se han probado usando la Native POSIX Thread Library (NTPL) en Linux (ubuntu), que implementa la parte de hebras de la versi´n de 2004 de POSIX o • Est´ disponible para Linux desde el kernel 2.6 (2004). a • En esta implementaci´n una hebra POSIX se implementa usando una hebra del kernel de Linux (se o dice que las hebras POSIX son 1-1). • Como consecuencia de lo anterior, hebras distintas de un mismo proceso pueden ejecutarse en procesadores distintos, • Por tanto, este tipo de hebras constituyen una herramienta ideal para el desarrollo de aplicaciones que pueden aprovechar el potencial de rendimiento que ofrecen los sistemas multiprocesador (o multin´cleo) u con memoria compartida. 6.2.2 Creaci´n y finalizaci´n de hebras o o Creaci´n de hebras con pthread create o Esta funci´n sirve para crear una nueva hebra, su declaraci´n es como sigue: o o § ¦ int pthread_create( pthread_t *thread, const pthread_attr_t *attr, void *(*start_routine)(void*), void *arg); Par´metros (m´s informaci´n aqu´ a a o ı): nombre thread tipo pthread t * start routine arg void *nombre(void *) void * attr attr t * Ejemplo de creaci´n de hebras. o ¤ ¥ descripci´n o para referencias posteriores en las operaciones sobre la hebra atributos de la hebra (puede ser NULL para valores por def.) funci´n a ejecutar por la hebra o puntero que se pasa como par´metro para start routine a (puede ser NULL). En el siguiente ejemplo se crean dos hebras: § #include <iostream> #include <pthread.h> using namespace std ; ¤ void* proc1( void* arg ) { for( unsigned long i = 0 ; i < 5000 ; i++ ) cout << "hebra 1, i == " << i << endl ; return NULL ; } creado October 4, 2013- p´gina 155 / 222 a
  • 156. SCD (13-14). Seminario 1. Programaci´n multihebra y sincronizaci´n con sem´foros.. o o a void* proc2( void* arg ) { for( unsigned long i = 0 ; i < 5000 ; i++ ) cout << "hebra 2, i == " << i << endl ; return NULL ; } int main() { pthread_t hebra1, hebra2 ; pthread_create(&hebra1,NULL,proc1,NULL); pthread_create(&hebra2,NULL,proc2,NULL); // ... finalizacion .... } ¦ ¥ Finalizaci´n de hebras o Una hebra finaliza cuando: • termina la funci´n designada en pthread create (solo para hebras distintas de la inicial, en estos casos o es equivalente a llamar a pthread exit). • llama a pthread exit expl´ ıcitamente • es terminada por otra hebra con una llamada a pthread cancel • el proceso (de esta hebra) termina debido a una llamada a exit desde cualquier hebra de dicho proceso. • la hebra inicial termina main sin haber llamado a pthread exit (es decir, para permitir que las hebras creadas contin´en al acabar la hebra inicial, es necesario que dicha hebra principal llame a pthread exit u antes del fin de main) La funci´n pthread exit o o La funci´n pthread exit causa la finalizaci´n de la hebra que la llama: o § void pthread_exit( void* value_ptr ); ¦ Par´metros: a nombre tipo value ptr void * m´s informaci´n: a o descripci´n o puntero que recibir´ la hebra que espere (v´ a ıa join) la finalizaci´n de esta hebra (si hay alguna) o (puede ser NULL) http://pubs.opengroup.org/onlinepubs/009695399/functions/pthread exit.html Ejemplo de pthread exit El ejemplo anterior se puede completar as´ ı: creado October 4, 2013- p´gina 156 / 222 a ¤ ¥
  • 157. SCD (13-14). Seminario 1. Programaci´n multihebra y sincronizaci´n con sem´foros.. o o a § #include <iostream> #include <pthread.h> using namespace std ; void* proc1( void* arg ) { for( unsigned long i = 0 ; i < 5000 ; i++ ) cout << "hebra 1, i == " << i << endl ; return NULL ; } void* proc2( void* arg ) { for( unsigned long i = 0 ; i < 5000 ; i++ ) cout << "hebra 2, i == " << i << endl ; return NULL ; } int main() { pthread_t hebra1, hebra2 ; pthread_create(&hebra1,NULL,proc1,NULL); pthread_create(&hebra2,NULL,proc2,NULL); pthread_exit(NULL); // permite continuar a hebra1 y hebra2 } ¦ 6.2.3 ¤ ¥ Sincronizaci´n mediante uni´n o o La operaci´n de uni´n. o o POSIX provee diversos mecanismos para sincronizar hebras, veremos dos de ellos: • Usando la operaci´n de uni´n (join). o o • Usando sem´foros. a La operaci´n de uni´n permite que (mediante una llamada a pthread join) una hebra A espere a que otra o o hebra B termine: • A es la hebra que invoca la uni´n, y B la hebra objetivo. o • Al finalizar la llamada, la hebra objetivo ha terminado con seguridad. • Si B ya ha terminado, no se hace nada. • Si la espera es necesaria, se produce sin que la hebra que llama (A) consuma CPU durante dicha espera (A queda suspendida). La funci´n pthread join o La funci´n pthread join est´ declarada como sigue: o a § int pthread_join( pthread_t thread, void **value_ptr ); ¦ creado October 4, 2013- p´gina 157 / 222 a ¤ ¥
  • 158. SCD (13-14). Seminario 1. Programaci´n multihebra y sincronizaci´n con sem´foros.. o o a Par´metros y resultado: a nombre thread value ptr resultado tipo thread t void ** int descripci´n o identificador de la hebra objetivo puntero a la variable que recibir´ el dato (de a tipo void *) enviado por la hebra objetivo al finalizar (v´ return o pthread exit) ıa 0 si no hay error, en caso contrario se devuelve un c´digo de error. o m´s informaci´n aqu´ http://pubs.opengroup.org/onlinepubs/009695399/functions/pthread join.html a o ı: Ejemplo de pthread join Puede ser util, por ejemplo, para que la hebra principal realice alg´n procesamiento posterior a la finalizaci´n ´ u o de las hebras: § #include <pthread.h> ¤ void* proc1( void* arg ) { /∗ .... ∗/ } void* proc2( void* arg ) { /∗ .... ∗/ } int main() { pthread_t hebra1, hebra2 ; pthread_create(&hebra1,NULL,proc1,NULL); pthread_create(&hebra2,NULL,proc2,NULL); pthread_join(hebra1,NULL); pthread_join(hebra2,NULL); } ¦ // calculo posterior a la finalizacion de las hebras..... 6.2.4 ¥ Par´metros e identificaci´n de hebras a o Hebras id´nticas e En muchos casos, un problema se puede resolver con un proceso en el que varias hebras distintas ejecutan el mismo algoritmo con distintos datos de entrada. En estos casos • Es necesario que cada hebra reciba par´metros distintos a • Esto se puede hacer a traves del par´metro de tipo void * que recibe el subprograma que ejecuta una a hebra. • Dicho par´metro suele ser un ´ a ındice o un puntero que permita a la hebra recuperar el conjunto de par´metros de entrada de una estructura de datos en memoria compartida, inicializada por la hebra a principal (si es un ´ ındice entero, es necesario convertirlo hacia/desde el tipo void *) • La estructura puede usarse para guardar tambi´n resultados de la hebra, o en general datos de la e misma que deban ser le´ ıdos por otras. creado October 4, 2013- p´gina 158 / 222 a
  • 159. SCD (13-14). Seminario 1. Programaci´n multihebra y sincronizaci´n con sem´foros.. o o a Ejemplo b´sico de paso de par´metros a hebras a a 10 hebras ejecutan concurrentemente func(0), func(1), . . . , func(9) § #include <iostream> #include <pthread.h> using namespace std ; ¤ const unsigned num_hebras = 10 ; unsigned long func( unsigned long n ) { /∗ ..calculo arbitrario.. ∗/ } void* proc( void* i ) { return (void *) func( (unsigned long)(i) ) ; } int main() { pthread_t id_hebra[num_hebras] ; for( unsigned i = 0 ; i < num_hebras ; i++ ) pthread_create( &(id_hebra[i]), NULL, proc, (void *)i ); for( unsigned i = 0 ; i < num_hebras ; i++ ) { unsigned long resultado ; pthread_join( id_hebra[i], (void **) (&resultado) ); cout << "func(" << i << ") == " << resultado << endl } ; } ¦ ¥ (nota: solo funciona si sizeof(unsigned long)==sizeof(void *)) 6.2.5 Ejemplo de hebras: c´lculo num´rico de integrales a e C´lculo de num´rico de integrales a e La programaci´n concurrente puede ser usada para resolver m´s r´pidamente multitud de problemas, entre o a a ellos los que conllevan muchas operaciones con n´meros flotantes u • Un ejemplo t´ ıpico es el c´lculo del valor I de la integral de una funci´n f de variable real (entre 0 y a o 1, por ejemplo ) y valores reales positivos: I = ∫ 0 1 f (x) dx • El c´lculo se puede hacer evaluando la funci´n f en un conjunto de m puntos uniformemente espaciados a o en el intervalo [0, 1], y aproximando I como la media de todos esos valores: I ≈ Interpretaci´n geom´trica o e 1 m−1 ∑ f (xi ) m i=0 donde: xi = i + 1/2 m Aproximamos el area azul (es I) (izquierda), usando la suma de las areas de las m barras (derecha): ´ ´ creado October 4, 2013- p´gina 159 / 222 a
  • 160. SCD (13-14). Seminario 1. Programaci´n multihebra y sincronizaci´n con sem´foros.. o o a y = f (x) y = f (x) x x • Cada punto de muestra es el valor xi (puntos negros) • Cada barra tiene el mismo ancho 1/m, y su altura es f (xi ). C´lculo secuencial del n´mero π a u Para verificar la correcci´n del m´todo, se puede usar una integral I con valor conocido. A modo de ejemplo, o e usaremos una funci´n f cuya integral entre 0 y 1 es el n´mero π: o u I = π = ∫ 1 0 4 dx 1 + x2 aqu´ f (x) = ı 4 1 + x2 una implementaci´n secuencial sencilla ser´ mediante esta funci´n: o ıa o § unsigned long m = ..... ; // n´mero de muestras u double f( double x ) // implementa funci´n f o { return 4.0/(1+x*x) ; // f (x) = 4/(1 + x2 ) } double calcular_integral_secuencial( ) { double suma = 0.0 ; // inicializar suma for( unsigned long i = 0 ; i < m ; i++ ) // para cada i entre 0 y m − 1 suma += f( (i+0.5)/m ); // a˜adir f (xi ) a la suma actual n return suma/m ; // devolver valor promedio de f } ¦ Versi´n concurrente de la integraci´n o o El c´lculo citado anteriormente se puede hacer mediante un total de n hebras id´nticas (asumimos que m a e es m´ltiplo de n) u • Cada una de las hebras evalua f en m/n puntos del dominio • La cantidad de trabajo es similar para todas, y los c´lculos son independientes. a creado October 4, 2013- p´gina 160 / 222 a ¤ ¥
  • 161. SCD (13-14). Seminario 1. Programaci´n multihebra y sincronizaci´n con sem´foros.. o o a • Cada hebra calcula la suma parcial de los valores de f • La hebra principal recoge las sumas parciales y calcula la suma total. • En un entorno con k procesadores o n´cleos, el c´lculo puede hacerse hasta k veces m´s r´pido. Esta u a a a mejora ocurre solo para valores de m varios ´rdenes de magnitud m´s grandes que n. o a Distribuci´n de c´lculos o a Para distribuir los c´lculos entre hebras, hay dos opciones simples, hacerlo de forma contigua (izquierda) o a de forma entrelazada (derecha) y = f (x) y = f (x) x x Cada valor f (xi ) es calculado por: • Contigua: la hebra n´mero i/n. u • Entrelazada: la hebra n´mero i mod n. u Esquema de la implementaci´n concurrente o § const unsigned long m = .... ; // n´mero de muestras u const unsigned long n = .... ; // n´mero de hebras u double resultado_parcial[n] ; // vector de resultados parciales double f( double x ) // implementa funci´n f : o { return 4.0/(1+x*x) ; // f (x) = 4/(1 + x2 ) } void * funcion_hebra( void * ih_void ) // funci´n que ejecuta cada hebra o { unsigned long ih = (unsigned long) ih_void ; // n´mero o ´ u ındice de esta hebra double sumap = 0.0 ; // calcular suma parcial en ”sumap” ..... resultado_parcial[ih] = sumap ; // guardar suma parcial en vector. } creado October 4, 2013- p´gina 161 / 222 a ¤
  • 162. SCD (13-14). Seminario 1. Programaci´n multihebra y sincronizaci´n con sem´foros.. o o a double calcular_integral_concurrente( ) { // crear y lanzar n hebras, cada una ejecuta ”funcion concurrente” ..... // esperar (join) a que termine cada hebra, sumar su resultado ..... // devolver resultado completo ..... } ¦ ¥ Medici´n de tiempos o Para apreciar la reducci´n de tiempos que se consigue con la programaci´n concurrente, se pueden medir o o los tiempos que tardan la versi´n secuencial y la concurrente. Para hacer esto con la m´xima precisi´n, se o a o puede usar la funci´n clock_gettime en linux: o • Forma parte de POSIX, en concreto de la extensiones de tiempo real. • Sirve para medir tiempo real transcurrido entre instantes de la ejecuci´n de un programa con muy alta o precisi´n (nanosegundos). o • Para facilitar su uso, en lugar de usarla directamente se pueden usar indirectamente a trav´s de otras e funciones (que se proporcionan) que permiten calcular ese tiempo como un valor real en segundos, haciendo abstracci´n de los detalles no relevantes. o Uso de las funciones de medici´n de tiempos o Para medir el tiempo que tarda un trozo de programa, se puede usar este esquema en C++ § #include "fun_tiempos.h" // .... void funcion_cualquiera( /∗.....∗/ ) { ..... struct timespec inicio = ahora() ; .... struct timespec fin = ahora() ; .... cout << "tiempo transcurrido == " << duracion( &inicio, &fin ) << " seg." << endl ; } ¦ ¤ // inicio = inicio del tiempo a medir // actividad cuya duracion se quiere medir // fin = fin del tiempo a medir // escribe resultados: // tiempo en segundos entre ”inicio” y ”fin” los archivos fun_tiempo.h (cabeceras) y fun_tiempo.c (implementaci´n) se encuentran disponibles para o los alumnos. Compilando programas con hebras POSIX Para compilar un archivo ejemplo.cpp, que use las funciones definidas en fun_tiempos.c (y use hebras posix), y obtener el archivo ejecutable ejemplo, podemos dar estos pasos: creado October 4, 2013- p´gina 162 / 222 a ¥
  • 163. SCD (13-14). Seminario 1. Programaci´n multihebra y sincronizaci´n con sem´foros.. o o a § gcc -g -c fun_tiempos.c # compila ”fun tiempos.c” y genera ”fun tiempos.o” g++ -g -c ejemplo.cpp # compila ”ejemplo.cpp” y genera ”ejemplo.o” g++ -o ejemplo ejemplo.o fun_tiempos.o -lrt -lpthread # enlaza, genera ”ejemplo” ¦ • el switch -lrt sirve para enlazar las librer´ correspondientes a la extensi´n de tiempo real de POSIX ıas o (incluye clock_gettime) • el switch -lpthreads sirve para incluir las funciones de hebras POSIX • tambi´n es posible integrarlo todo en un makefile y usar make e Actividad: medici´n de tiempos de c´lculo concurrente. o a Como actividad para los alumnos en este seminario se propone realizar y ejecutar una implementaci´n sencilla o del c´lculo concurrente del n´mero π, tal y como hemos visto aqu´ a u ı: • El programa aceptar´ como par´metros en la l´ a a ınea de comandos el n´mero de hebras a lanzar y el u n´mero de muestras u • En la salida se presenta el valor exacto de π y el calculado (sirve para verificar si el programa es correcto, ya que deben diferir por muy poco para un n´mero de muestras del orden de cientos o miles) u • Asimismo , el programa imprimir´ la duraci´n del c´lculo concurrente y el secuencial. a o a Se debe razonar acerca de como el n´mero de procesadores disponibles y el n´mero de hebras afecta u u al tiempo del c´lculo concurrente en relaci´n al secuencial (en Linux, para conocer el n´mero de CPUs a o u disponibles y sus caracter´ ısticas, se puede ver el archivo /proc/cpuinfo) 6.3 Introducci´n a los Sem´foros o a Sem´foros a Los sem´foros constituyen un mecanismo de nivel medio que permite solucionar los problemas derivados de a la ejecuci´n concurrente de procesos no independientes. Sus caracter´ o ısticas principales son: • permite bloquear los procesos sin mantener ocupada la CPU • resuelven f´cilmente el problema de exclusi´n mutua con esquemas de uso sencillos a o • se pueden usar para resolver problemas de sincronizaci´n (aunque en ocasiones los esquemas de uso o son complejos) • el mecanismo se implementa mediante instancias de una estructura de datos a las que se accede unicamente mediante subprogramas espec´ ´ ıficos. creado October 4, 2013- p´gina 163 / 222 a ¤ ¥
  • 164. SCD (13-14). Seminario 1. Programaci´n multihebra y sincronizaci´n con sem´foros.. o o a Estructura de un sem´foro a Un sem´foro es un instancia de una estructura de datos (un registro) que contiene los siguientes elementos: a • Un conjunto de procesos bloqueados (se dice que est´n esperando en el sem´foro). a a • Un valor natural (entero no negativo), al que llamaremos valor del sem´foro a Estas estructuras de datos residen en memoria compartida. Al principio de un programa que use sem´foros, a debe poder inicializarse cada uno de ellos: • el conjunto de procesos asociados (bloqueados) estar´ vac´ a ıo • se deber´ indicar un valor inicial del sem´foro a a Operaciones sobre los sem´foros a Adem´s de la inicializaci´n, solo hay dos operaciones b´sicas que se pueden realizar sobre una variable de a o a tipo sem´foro (que llamamos s) : a • sem wait(s) ◾ Si el valor de s es mayor que cero, decrementar en una unidad dicho valor ◾ Si el valor de s es cero, bloquear el proceso que la invoca en el conjunto de procesos bloqueados asociado a s • sem signal(s) ◾ Si el conjunto de procesos bloqueados asociado a s no est´ vac´ desbloquear uno de dichos a ıo, procesos. ◾ Si el conjunto de procesos bloqueados asociado a s est´ vac´ incrementar en una unidad el valor a ıo, de s. En un sem´foro cualquiera, estas operaciones se ejecutan de forma at´mica, es decir, no puede haber dos a o procesos distintos ejecutando estas operaciones a la vez sobre un mismo sem´foro (excluyendo el per´ a ıodo de bloqueo que potencialmente conlleva la llamada a sem wait). Uso de sem´foros para exclusi´n mutua a o Los sem´foros se pueden usar para EM usando un sem´foro inicializado a 1, y haciendo sem wait antes de a a e o ıtica: la secci´n cr´ o ıtica y sem signal despu´s de la secci´n cr´ § { variables compartidas y valores iniciales } var sc_libre : semaphore := 1 ; { 1 si SC esta libre, 0 si SC esta ocupada } ¦ § while true do begin sem_wait( sc_libre ); { esperar bloqueado hasta que ’sc libre’ sea 1 } { seccion critica : ...... } sem_signal( sc_libre ); { desbl. proc. en espera o poner ’sc libre’ a 1 } { resto seccion : ....... } end ¦ En cualquier instante de tiempo, la suma del valor del sem´foro m´s el n´mero de procesos en la SC es la a a u unidad. Por tanto, solo puede haber 0 o 1 procesos en SC, y se cumple la exclusi´n mutua. o creado October 4, 2013- p´gina 164 / 222 a ¤ ¥ ¤ ¥
  • 165. SCD (13-14). Seminario 1. Programaci´n multihebra y sincronizaci´n con sem´foros.. o o a Uso de sem´foros para sincronizaci´n a o El problema del Productor-Consumidor se puede resolver f´cilmente con sem´foros: a a § { variables compartidas var x : producidos : consumidos : puede_leer : puede_escribir : ¦ integer ; integer integer semaphore semaphore := := := := 0 0 0 1 ; ; ; ; { { { { { § { Proceso Productor ( calcula ”x ”) } var a : integer ; begin while true begin a := ProducirValor() ; sem_wait( puede_escribir ); x := a ; { sentencia E } producidos := producidos + 1 ; sem_signal( puede_leer ) ; end end ¦ 6.4 ¤ } contiene cada valor producido } numero de valores producidos } numero de valores consumidos } 1 si se puede leer ”x”, 0 si no } 1 si se puede escribir ”x”, 0 si no } ¤ § { Proceso Consumidor (lee ”x ”) } var b : integer ; begin while true do begin sem_wait( puede_leer ) ; b := x ; { sentencia L } consumidos := consumidos + 1 ; sem_signal( puede_escribir ) ; UsarValor(b) ; end end ¥ ¦ ¥ ¤ ¥ Sincronizaci´n de hebras con sem´foros POSIX o a Introducci´n o Una parte de las llamadas del est´ndard POSIX son utiles para gestionar sem´foros para sincronizaci´n de a ´ a o hebras o de procesos. Veremos las llamadas b´sicas que permiten sincronizar hebras en un proceso. Son las siguientes: a • sem init: inicializa un sem´foro (dando el valor inicial) a • sem wait: realiza la operaci´n wait sobre un sem´foro o a • sem post: realiza la operaci´n signal sobre un sem´foro o a • sem getvalue: devuelve el valor actual de un sem´foro a • sem destroy: destruye un sem´foro y libera la memoria ocupada. a 6.4.1 Funciones b´sicas. a La funci´n sem init o La funci´n sem init est´ declarada como sigue: o a § int sem_init( sem_t* sem, int pshared, unsigned value ); ¦ creado October 4, 2013- p´gina 165 / 222 a ¤ ¥
  • 166. SCD (13-14). Seminario 1. Programaci´n multihebra y sincronizaci´n con sem´foros.. o o a Par´metros y resultado: a nombre sem pshared value resultado tipo sem t * int unsigned int descripci´n o puntero al identificador del sem´foro a distinto de cero solo si el sem´foro a ser´ compartido con otros procesos. a valor inicial 0 si se ha inicializado el sem´foro, en caso a contrario es un c´digo de error. o m´s informaci´n aqu´ http://pubs.opengroup.org/onlinepubs/009695399/functions/sem init.html a o ı: La funci´n sem wait o a La funci´n sem wait est´ declarada como sigue: o § int sem_wait( sem_t* sem ); ¦ ¤ ¥ Par´metros y resultado: a nombre sem resultado tipo sem t * int descripci´n o puntero al identificador del sem´foro a 0 solo si no ha habido error m´s informaci´n aqu´ http://pubs.opengroup.org/onlinepubs/009695399/functions/sem wait.html a o ı: La funci´n sem post o a La funci´n sem post est´ declarada como sigue: o § int sem_post( sem_t* sem ); ¦ ¤ ¥ Par´metros y resultado: a nombre sem resultado tipo sem t * int descripci´n o puntero al identificador del sem´foro a 0 solo si no ha habido error Nota: la selecci´n de la hebra a desbloquear (si hay alguna) depende de los parametros de scheduling o asignados a la hebra (normalmente es FIFO). M´s informaci´n aqu´ http://pubs.opengroup.org/onlinepubs/009695399/functions/sem post.html a o ı: La funci´n sem getvalue o La funci´n sem getvalue est´ declarada como sigue: o a § int sem_getvalue( sem_t* sem, int* sval ); ¦ ¤ ¥ Par´metros y resultado: a creado October 4, 2013- p´gina 166 / 222 a
  • 167. SCD (13-14). Seminario 1. Programaci´n multihebra y sincronizaci´n con sem´foros.. o o a nombre sem sval resultado tipo sem t * int * int descripci´n o puntero al identificador del sem´foro a puntero a la variable donde se almacena el valor 0 solo si no ha habido error Nota: al finalizar la llamada, el valor del sem´foro podr´ ya ser distinto del valor le´ (es importante a ıa ıdo tenerlo en cuenta). M´s informaci´n aqu´ http://pubs.opengroup.org/onlinepubs/009695399/functions/sem getvalue.html a o ı: La funci´n sem destroy o La funci´n sem destroy est´ declarada como sigue: o a § int sem_destroy( sem_t* sem ) ; ¦ ¤ ¥ Par´metros y resultado: a nombre sem resultado tipo sem t * int descripci´n o puntero al identificador del sem´foro a 0 solo si no ha habido error Solo se aplica a sem´foros inicializados con sem init en los cuales no hay hebras esperando. Despu´s de a e destruir un sem´foro, se puede reusar haciendo sem init. a M´s informaci´n aqu´ http://pubs.opengroup.org/onlinepubs/009695399/functions/sem destroy.html a o ı: 6.4.2 Exclusi´n mutua o Ejemplo de exclusi´n mutua con sem´foros POSIX o a Los sem´foros se pueden usar para exclusi´n mutua, por ejemplo, a o En este ejemplo, se usa un sem´foro (de nombre mutex) inicializado a 1, para escribir en la salida est´ndar a a una l´ ınea completa sin interrupciones. § #include <iostream> #include <pthread.h> #include <semaphore.h> using namespace std ; ¤ sem_t mutex ; // semaforo en memoria compartida void* proc( void* p ) { sem_wait( &mutex ); cout << "hebra numero: " << ((unsigned long) p) << ". " << endl ; sem_post( &mutex ); return NULL ; } .... ¦ ¥ creado October 4, 2013- p´gina 167 / 222 a
  • 168. SCD (13-14). Seminario 1. Programaci´n multihebra y sincronizaci´n con sem´foros.. o o a Ejemplo de exclusi´n mutua con sem´foros POSIX (2) o a El procedimiento principal debe inicializar el sem´foro y crear las hebras, como se incluye aqu´ a ı: § ... ¤ int main() { const unsigned num_hebras = 50 ; pthread_t id_hebra[num_hebras] ; sem_init( &mutex, 0, 1 ); for( unsigned i = 0 ; i < num_hebras ; i++ ) pthread_create( &(id_hebra[i]), NULL, proc, (void *)i ); for( unsigned i = 0 ; i < num_hebras ; i++ ) pthread_join( id_hebra[i], NULL ); sem_destroy( &mutex ); } ¦ 6.4.3 ¥ Sincronizaci´n o Ejemplo de sincronizaci´n con sem´foros POSIX o a En este otro ejemplo, hay una hebra que escribe una variable global y otra que la lee (cada una en un bucle). Se usan dos sem´foros para evitar dos lecturas o dos escrituras seguidas, y adem´s otro para exclusi´n m´tua a a o u en las escrituras al terminal: § sem_t puede_escribir, // inicializado a 1 puede_leer, // inicializado a 0 mutex ; // inicializado a 1 ¤ unsigned long valor_compartido ; // valor para escribir o leer const unsigned long num_iter = 10000 ; // numero de iteraciones ...... ¦ ¥ Ejemplo de sincronizaci´n con sem´foros POSIX (2) o a La hebra escritora espera que se pueda escribir, entonces escribe y se˜ala que se puede leer: n § ... void* escribir( void* p ) { creado October 4, 2013- p´gina 168 / 222 a ¤
  • 169. SCD (13-14). Seminario 1. Programaci´n multihebra y sincronizaci´n con sem´foros.. o o a unsigned long contador = 0 ; for( unsigned long i = 0 ; i < { contador = contador + 1 ; // sem_wait( &puede_escribir ) valor_compartido = contador sem_post( &puede_leer ) ; num_iter ; i++ ) genera un nuevo valor ; ; // escribe el valor sem_wait( &mutex ) ; cout << "valor escrito == " << contador << endl << flush ; sem_post( &mutex ) ; } return NULL ; } ... ¦ ¥ Ejemplo de sincronizaci´n con sem´foros POSIX (3) o a La hebra lectora espera a que se pueda leer, entonces lee y se˜ala que se puede escribir: n § .... ¤ void* leer( void* p ) { unsigned long valor_leido ; for( unsigned long i = 0 ; i < num_iter ; i++ ) { sem_wait( &puede_leer ) ; valor_leido = valor_compartido ; // lee el valor generado sem_post( &puede_escribir ) ; sem_wait( &mutex ) ; cout << "valor leido sem_post( &mutex ) ; == " << valor_leido << endl << flush ; } return NULL ; } ... ¦ ¥ Ejemplo de sincronizaci´n con sem´foros POSIX (4) o a El procedimiento main crea los sem´foros y hebras y espera que terminen: a § .... int main() { creado October 4, 2013- p´gina 169 / 222 a ¤
  • 170. SCD (13-14). Pr´ctica 1. Sincronizaci´n de hebras con sem´foros.. a o a pthread_t hebra_escritora, hebra_lectora ; sem_init( &mutex, 0, 1 ) ; // semaforo para EM: inicializado a 1 sem_init( &puede_escribir, 0, 1); // inicialmente se puede escribir sem_init( &puede_leer, 0, 0); // inicialmente no se puede leer pthread_create( &hebra_escritora, NULL, escribir, NULL ); pthread_create( &hebra_lectora, NULL, leer, NULL ); pthread_join( hebra_escritora, NULL ) ; pthread_join( hebra_lectora, NULL ) ; sem_destroy( &puede_escribir ); sem_destroy( &puede_leer ); } ¦ ¥ creado October 4, 2013- p´gina 170 / 222 a
  • 171. Chapter 7 Pr´ctica 1. Sincronizaci´n de hebras con a o sem´foros. a 7.1 Objetivos Objetivos. En esta pr´ctica se realizar´n dos implementaciones de dos problemas sencillos de sincronizaci´n usando a a o librer´ abiertas para programaci´n multihebra y sem´foros. Los objetivos son: ıas o a • Conocer el problema del productor-consumidor y sus aplicaciones. ◾ Dise˜ar una soluci´n al problema basada en sem´foros. n o a ◾ Implementar esa soluci´n en un programa C/C++ multihebra, usando la funcionalidad de la o librer´ POSIX para: ıa ▸ la creaci´n y destrucci´n de hebras o o ▸ la sincronizaci´n de hebras usando sem´foros o a • Conocer un problema sencillo de sincronizaci´n de hebras (el problema de los fumadores) o ◾ Dise˜ar una soluci´n basada en sem´foros, teniendo en cuenta los problemas que pueden aparen o a cer. 7.2 7.2.1 ◾ Implementar la soluci´n a dicho problema en C/C++ usando hebras y sem´foros POSIX. o a El problema del productor-consumidor Descripci´n del problema. o Problema y aplicaciones El problema del productor consumidor surge cuando se quiere dise˜ar un programa en el cual un proceso o n hebra produce items de datos en memoria que otro proceso o hebra consume. • Un ejemplo ser´ una aplicaci´n de reproducci´n de v´ ıa o o ıdeo: 171
  • 172. SCD (13-14). Pr´ctica 1. Sincronizaci´n de hebras con sem´foros.. a o a ◾ El productor se encarga de leer de disco o la red y descodificar cada cuadro de v´ ıdeo. ◾ El consumidor lee los cuadros descodificados y los env´ a la memoria de v´ ıa ıdeo para que se muestren en pantalla hay muchos ejemplos de situaciones parecidas. • En general, el productor calcula o produce una secuencia de items de datos (uno a uno), y el consumidor lee o consume dichos items (tambien uno a uno). • El tiempo que se tarda en producir un item de datos puede ser variable y en general distinto al que se tarda en consumirlo (tambi´n variable). e Soluci´n de dos hebras con un vector de items o Para dise˜ar un programa que solucione este problema: n • Suele ser conveniente implementar el productor y el consumidor como dos hebras independientes, ya que esto permite tener ocupadas las CPUs disponibles el m´ximo de tiempo, a • se puede usar una variable compartida que contiene un ´ ıtem de datos, • las esperas asociadas a la lectura y la escritura pueden empeorar la eficiencia. Esto puede mejorarse usando un vector que pueda contener muchos items de datos producidos y pendientes de leer. Condici´n de sincronizaci´n o o En esta situaci´n, la implementaci´n debe asegurar que : o o • cada ´ ıtem producido es le´ (ning´n ´ ıdo u ıtem se pierde) • ning´n ´ u ıtem se lee m´s de una vez. a lo cual implica: • el productor tendr´ que esperar antes de poder escribir en el vector cuando haya creado un ´ a ıtem pero el vector est´ completamente ocupado por ´ e ıtems pendientes de leer • el consumidor debe esperar cuando vaya a leer un ´ ıtem del vector pero dicho vector no contenga ning´n u ´ ıtem pendiente de leer. • en algunas aplicaciones el orden de lectura debe coincidir con el de escritura, en otras podr´ ser ıa irrelevante. 7.2.2 Plantillas de c´digo o Simplificaciones En esta pr´ctica se dise˜ar´ e implementar´ un ejemplo sencillo en C/C++ a n a a • cada ´ ıtem de datos ser´ un valor entero de tipo int, a creado October 4, 2013- p´gina 172 / 222 a
  • 173. SCD (13-14). Pr´ctica 1. Sincronizaci´n de hebras con sem´foros.. a o a • el orden en el que se leen los items es irrelevante (en principio), • el productor produce los valores enteros en secuencia, empezando en 1, • el consumidor escribe cada valor le´ en pantalla, ıdo • se usar´ un vector intermedio de valores tipo int, de tama˜o fijo pero arbitrario. a n Funciones para producir y consumir: Para producir un item de datos, la hebra productora invocar´ esta funci´n: a o § int producir_dato() { static int contador = 1 ; return contador ++ ; } ¦ ¤ ¥ mientras que la hebra consumidora llama a esta otra para consumir un dato: § void consumir_dato( int dato ) { cout << "dato recibido: " << dato << endl ; } ¦ ¤ ¥ Hebras productora y consumidora Los subprogramas que ejecutan las hebras productora y consumidora son como se indica a continuaci´n (no o se incluye la sincronizaci´n ni los accesos al vector): o § void * productor( void * ) { for( unsigned i = 0 ; i < num_items ; i++ ) { int dato = producir_dato() ; // falta: insertar ”dato” en el vector } return NULL ; } void * consumidor( void * ) { for( unsigned i = 0 ; i < num_items ; i++ ) { int dato ; // falta: leer ”dato” desde el vector intermedio consumir_dato( dato ) ; } return NULL ; } ¦ ¤ ¥ Es necesario definir la constante num items con alg´n valor concreto (entre 50 y 100 es adecuado) u Gesti´n de la ocupaci´n del vector intermedio o o El vector intermedio (buffer) tiene una capacidad (n´mero de celdas usables) fija prestablecidada en una u constante del programa que llamamos, por ejemplo, tam_vec. creado October 4, 2013- p´gina 173 / 222 a
  • 174. SCD (13-14). Pr´ctica 1. Sincronizaci´n de hebras con sem´foros.. a o a • La constente tam_vec deber´ ser estrictamente menor que num_items (entre 10 y 20 ser´ adecuado). a ıa • En cualquier instante de la ejecuci´n, el n´mero de celdas ocupadas en el vector (por items de datos o u producidos pero pendientes de leer) es un n´mero entre 0 (el buffer estar´ vac´ y tam_vec (el buffer u ıa ıo) estar´ lleno). ıa • Adem´s del vector, es necesario usar alguna o algunas variables adicionales que reflejen el estado de a ocupaci´n de dicho vector. o • Es necesario estudiar si el acceso a dicha variable o variables requiere o no requiere sincronizaci´n o alguna entre el productor y el consumidor. Soluciones para la gesti´n de la ocupaci´n o o Hay b´sicamente dos alternativas posibles para gestionar la ocupaci´n, se detallan aqu´ a o ı: • LIFO (pila acotada), se usa una unica variable entera no negativa: ´ ◾ primera_libre = ´ ındice en el vector de la primera celda libre (inicialmente 0). Esta variable se incrementa al escribir, y se decrementa al leer. • FIFO (cola circular), se usan dos variables enteras no negativas: ◾ primera_ocupada = ´ ındice en el vector de la primera celda ocupada (inicialmente 0). Esta variable se incrementa al leer (m´dulo tam_vector). o ◾ primera_libre = ´ ındice en el vector de la primera celda libre (inicialmente 0). Esta variable se incrementa al escribir (m´dulo tam_vector). o (asumismos que los ´ ındices del vector van desde 0 hasta tam_vector-1, ambos incluidos) 7.2.3 Actividades y documentaci´n o Lista de actividades Debes realizar las siguientes actividades en el orden indicado: 1. Dise˜a una soluci´n que permita conocer qu´ entradas del vector est´n ocupadas y qu´ entradas est´n n o e a e a libres (usa alguna de las dos opciones dadas). 2. Dise˜a una soluci´n, mediante sem´foros, que permita realizar las esperas necesarias para cumplir los n o a requisitos descritos. 3. Implementa la soluci´n descrita en un programa C/C++ con hebras y sem´foros POSIX, completando o a las plantillas incluidas en este gui´n. Ten en cuenta que el programa debe escribir la palabra fin o cuando hayan terminado las dos hebras. 4. Comprueba que tu programa es correcto: verifica que cada n´mero natural producido es consumido u exactamente una vez. creado October 4, 2013- p´gina 174 / 222 a
  • 175. SCD (13-14). Pr´ctica 1. Sincronizaci´n de hebras con sem´foros.. a o a Documentaci´n a incluir dentro del portafolios o Se incorporar´ al portafolios un documento indicando la siguiente informaci´n: a o 1. Describe la variable o variables necesarias, y c´mo se determina en qu´ posici´n se puede escribir y o e o en qu´ posici´n se puede leer. e o 2. Describe los sem´foros necesarios, la utilidad de los mismos, el valor inicial y en qu´ puntos del a e programa se debe usar sem wait y sem signal sobre ellos. 3. Incluye el c´digo fuente completo de la soluci´n adoptada. o o 7.3 7.3.1 El problema de los fumadores. Descripci´n del problema. o Descripci´n del problema (1) o En este apartado se intenta resolver un problema algo m´s complejo usando hebras y sem´foros POSIX. a a Considerar un estanco en el que hay tres fumadores y un estanquero. 1.1. Cada fumador representa una hebra que realiza una actividad (fumar), invocando a una funci´n fumar(), o en un bucle infinito. 1.2. Cada fumador debe esperar antes de fumar a que se den ciertas condiciones (tener suministros para fumar), que dependen de la actividad del proceso que representa al estanquero. 1.3. El estanquero produce suministros para que los fumadores puedan fumar, tambi´n en un bucle infinito. e 1.4. Para asegurar concurrencia real, es importante tener en cuenta que la soluci´n dise˜ada debe permitir o n que varios fumadores fumen simult´neamente. a Descripci´n del problema (2) o A continuaci´n se describen los requisitos para que los fumadores puedan fumar y el funcionamiento del o proceso estanquero: 2.1. Antes de fumar es necesario liar un cigarro, para ello el fumador necesita tres ingredientes: tabaco, papel y cerillas. 2.2. Uno de los fumadores tiene solamente papel, otro tiene solamente tabaco, y el otro tiene solamente cerillas. 2.3. El estanquero coloca aleatoriamente dos ingredientes diferentes de los tres que se necesitan para hacer un cigarro, desbloquea al fumador que tiene el tercer ingrediente y despu´s se bloquea. e 2.4. El fumador desbloqueado toma los dos ingredientes del mostrador, desbloquea al estanquero para que pueda seguir sirviendo ingredientes y fuma durante un tiempo despu´s de liarse el cigarro. e 2.5. El estanquero, cuando se desbloquea, vuelve a poner dos ingredientes aleatorios en el mostrador, y se repite el ciclo. creado October 4, 2013- p´gina 175 / 222 a
  • 176. SCD (13-14). Seminario 2. Hebras en Java.. 7.3.2 Plantillas de c´digo o Simulaci´n de la acci´n de fumar o o Para simular la acci´n de fumar, fumar(), se puede usar la funci´n unsigned sleep(unsigned segundos) que o o suspende a la hebra que la invoca tantos segundos como indica su unico argumento. Para que el retardo ´ sea aleatorio, se puede tomar como referencia el siguiente fragmento c´digo: o § #include <time.h> // incluye ”time(....)” #include <unistd.h> // incluye ”sleep(....)” #include <stdlib.h> // incluye ”rand(...)” ¤ // funci´n que simula la acci´n de fumar o o // como un retardo aleatorio de la hebra void fumar() { sleep( rand() % 5 ); } // ...... int main() { srand ( time(NULL) ); // inicializa la semilla aleatoria // .... } ¦ 7.3.3 ¥ Actividades y documentaci´n. o Dise˜o de la soluci´n n o Dise˜a e implementa una soluci´n al problema en C/C++ usando cuatro hebras y los sem´foros necesarios. n o a La soluci´n debe cumplir los requisitos incluidos en la descripci´n, y adem´s debe: o o a • Evitar interbloqueos entre las distintas hebras. • Producir mensajes en la salida est´ndar que permitan hacer un seguimiento de la actividad de las a hebras: ◾ El estanquero debe indicar cu´ndo produce suministros y qu´ suministros produce. Para esa e tablecer los ingredientes concretos (o directamente el fumador que podr´ usarlos), se debe usar ıa tambi´n la funci´n rand(). e o ◾ Cada fumador debe indicar cu´ndo espera, qu´ producto o productos espera, y cu´ndo comienza a e a y finaliza de fumar. Documentaci´n a incluir dentro del portafolios o Se incorporar´ al portafolios un documento incluyendo los siguientes puntos: a 1. Sem´foros necesarios para sincronizaci´n y para cada uno de ellos: a o • Utilidad. • Valor inicial. • Hebras que hacen sem wait y sem signal sobre dicho sem´foro. a creado October 4, 2013- p´gina 176 / 222 a
  • 177. SCD (13-14). Seminario 2. Hebras en Java.. 2. C´digo fuente completo de la soluci´n adoptada. o o creado October 4, 2013- p´gina 177 / 222 a
  • 178. SCD (13-14). Seminario 2. Hebras en Java.. creado October 4, 2013- p´gina 178 / 222 a
  • 179. Chapter 8 Seminario 2. Hebras en Java. Introducci´n o Este seminario es una breve introducci´n a la programaci´n con hebras en el lenguaje Java. o o • El objetivo es conocer las principales formas de crear y gestionar y hebras en Java, con objeto de desarrollar los ejemplos de la pr´ctica 2. a • Se mostrar´n las distintas formas de crear hebras en Java, los distintos estados de una hebra Java y a c´mo controlar la prioridad de las hebras. o • Se ver´ un mecanismo para asegurar la exclusi´n mutua en el acceso concurrente a bloques de c´digo a o o Java. Enlaces para acceder a informaci´n complementaria o • Aprenda Java como si Estuviera en primero. • Tutorial de Java. • Manual de Java. • Informaci´n sobre la clase Thread. o 179
  • 180. SCD (13-14). Seminario 2. Hebras en Java.. 8.1 Hebras en Java Concepto de hebra en Java • La mayor´ de las implementaciones de Java incluyen un compilador que genera c´digo intermedio ıa o independiente de la m´quina (llamado bytecode) m´s un int´rprete de dicho c´digo intermedio. a a e o • El bytecode es interpretado por un proceso denominado M´quina Virtual Java (JVM). a • Las hebras Java se ejecutan dentro de la JVM y comparten los recursos de este proceso del sistema operativo. • Java ofrece una interfaz para manejar hebras. • Una hebra Java es una instancia de una clase que implementa la interfaz Runnable, y/o instancias de una subclase de la clase Thread. • Los m´todos de las clases Thread y Object (definidas en el paquete java.lang) son los que e hacen posible la gesti´n y sincronizaci´n de hebras en Java. o o Ejecuci´n de una hebra en Java o a) Por defecto, al ejecutar un programa Java, tenemos una hebra asociada al m´todo main(), que va e recorriendo distintos objetos conforme se invocan los correspondientes m´todos. e b) Dentro de la hebra main, se pueden crear varias hebras que pueden ejecutar m´todos del mismo o de e diferentes objetos en el mismo o en diferente momento. a) 8.2 b) Creaci´n de hebras en Java o Creaci´n de hebras en Java o Para ejecutar una hebra en Java es necesario definir (al menos) una clase C que contenga un m´todo run. e Cada hebra ejecuta el c´digo de dicho m´todo para una instancia de C. Esto se puede implementar de dos o e formas: creado October 4, 2013- p´gina 180 / 222 a
  • 181. SCD (13-14). Seminario 2. Hebras en Java.. • C es una clase derivada de la clase Thread: ◾ Thread es una clase predefinida en el lenguaje. ◾ Se impide que C sea derivada de otra clase distinta de Thread. • C es una clase que implementa la interfaz Runnable: ◾ Runnable es un interfaz predefinido en el lenguaje. ◾ C puede extender (ser derivada de) una clase base cualquiera. ◾ Se requiere adicionalmente la creaci´n de una instancia de Thread por cada hebra a ejecutar. o Esta instancia guarda una referencia a la instancia de C. Nosotros usaremos la segunda opci´n precisamente por su mayor flexibilidad, a pesar de que es ligeramente o m´s complejo. Habr´ tantas clases C como sea necesario. a a Uso de Runnable y Thread Por cada hebra a ejecutar es necesario crear, adem´s de una instancia r de C, una instancia t de Thread (t a contiene una referencia a r). Hay dos posibilidades: • El objeto r y despu´s t se crean de forma independiente en la aplicaci´n como dos objetos distintos. e o • La clase C incluye como variable de instancia el objeto t (el objeto r tiene una referencia a t, o bien decimos que el objeto Runnable encapsula al objeto Thread). nosotros usaremos la segunda opci´n ya que fuera del c´digo de C solo tendremos que gestionar un objeto o o C en lugar de dos de ellos (uno C y otro Thread). Creaci´n y ejecuci´n de una hebra. o o Definiremos una clase TipoHebra, la cual • puede ser derivada de una clase base Base cualquiera (no es necesario). • tiene una variable de instancia p´blica de nombre, por ejemplo, thr, de la clase Thread. u • en su constructor crea el objeto thr. Para ejecutar una de estas hebras es necesario: 1. Declarar una instancia obj de la clase TipoHebra (internamente se crea obj.thr). 2. Usar el m´todo start de Thread sobre obj.thr, es decir, ejecutar obj.thr.start(). e La nueva hebra comienza la ejecuci´n concurrente de obj.run(). o creado October 4, 2013- p´gina 181 / 222 a
  • 182. SCD (13-14). Seminario 2. Hebras en Java.. Ejemplo de una hebra La definici´n de TipoHebra puede, a modo de ejemplo, ser as´ o ı: § class TipoHebra implements Runnable // opcionalmente: extends .... { long siesta ; // tiempo que duerme la hebra public Thread thr ; // objeto hebra encapsulado 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 } ¦ ¤ public TipoHebra( String nombre, long siesta ) { this.siesta = siesta; thr = new Thread( this, nombre ); } public void run() { try { while ( true ) { System.out.println( "Hola, soy "+thr.getName() ); if ( siesta > 0 ) Thread.sleep( siesta ); } } catch ( InterruptedException e ) { System.out.println( "me fastidiaron la siesta!" ); } } ¥ Programa principal Lanza una hebra y despu´s hace join (la espera) y getName. e § class Principal1 { public static void main( String[] args ) throws InterruptedException { if ( args.length < 1 ) { System.out.println( "Error: falta valor de ’siesta’" ); System.exit(1); } long siesta = Long.parseLong( args[0] ) ; TipoHebra obj = new TipoHebra("hebra ’obj’", siesta); // crear hebra 23 24 25 26 27 28 29 30 31 32 33 34 obj.thr.start(); // lanzar hebra 35 Thread.sleep( 100 ); // la hebra principal duerme 1/10 sec. 36 obj.thr.join(); // esperar a que termine la hebra 37 } 38 } ¦ 8.3 Estados de una hebra Java Estados de una hebra Java creado October 4, 2013- p´gina 182 / 222 a ¤ ¥
  • 183. SCD (13-14). Seminario 2. Hebras en Java.. • Nueva: Cuando el objeto hebra es creado, por ejemplo con: § ¦ Thread thr = new Thread (a); • Ejecutable: Cuando se invoca al m´todo start de una nueva hebra: e § ¦ thr.start (); • En ejecuci´n: Cuando la hebra est´ ejecut´ndose en alguna CPU del computador. Si una hebra en o a a este estado ejecuta el m´todo yield, deja la CPU y pasa el estado ejecutable: e § ¦ Thread.yield (); // metodo static de la clase Thread • Bloqueada: Una hebra pasa a este estado: ◾ cuando llama al m´todo sleep, volviendo al estado ejecutable cuando retorne la llamada: e § ¦ Thread.sleep (tiempo_milisegundos}; // metodo est´tico a ◾ cuando llama a wait dentro de un bloque o un m´todo sincronizado, volviendo al estado ejecutable e cuando otra hebra llame a notify o a notifyAll ◾ cuando llama a join para sincronizarse con la terminaci´n de otra hebra que a´n no ha terminado: o u § ¤ ¥ ¤ ¥ ¤ ¥ ¤ ¥ ¤ thr.join (); ¦ ◾ cuando ejecuta alguna operaci´n de e/s bloqueante. o • Muerta: Cuando su m´todo run termina. e Transiciones entre estados El siguiente diagrama muestra de forma resumida las diferentes transiciones entre estados y los m´todos e que los provocan: creado October 4, 2013- p´gina 183 / 222 a ¥
  • 184. SCD (13-14). Seminario 2. Hebras en Java.. 8.4 Prioridades y planificaci´n. o Prioridad de una hebra • Cada hebra tiene una prioridad que afecta a su planificaci´n. Una hebra hereda la prioridad de la hebra o que la cre´. La prioridad es un valor entero entre Thread.MIN_PRIORITY y Thread.MAX_PRIORITY o (dos constantes). • La prioridad actual de una hebra puede obtenerse invocando el m´todo getPriority, y se modifica e con setPriority. En el ejemplo creamos una hebra y decrementamos su prioridad antes de llamar a start: § ¦ thr = new Thread( obj ); thr.setPriority( thr.getPriority()-1 ); thr.start(); ¤ ¥ Planificaci´n de hebras o • El planificador de hebras de Java asegura que la hebra ejecutable con mayor prioridad (o una de ellas, si hay varias) pueda ejecutarse en la CPU. Si una hebra con mayor prioridad que la actual pasa a estar en estado ejecutable, la hebra actual pasa al estado ejecutable, y la hebra ejecutable de mayor prioridad es ejecutada (se apropia de la CPU). • Si la hebra actual invoca a yield, se suspende, o se bloquea, el planificador elige para ejecuci´n la o pr´xima hebra de mayor prioridad. o • Otro aspecto de la planificaci´n es el tiempo compartido, es decir la alternancia en el uso de la CPU o por parte de las hebras ejecutables de mayor prioridad. 8.4.1 Un ejemplo m´s completo a Ejemplo de un vector de hebras. El este ejemplo se crea un array de hebras de acuerdo con el esquema visto en la primera secci´n. Cada o hebra es una instancia de Dormilona: § 44 class Dormilona implements Runnable 45 { 46 int vueltas = 0 ; // n´mero de veces que duerme (0 == infinitas) u 47 int siesta = 0 ; // tiempo m´ximo que duerme cada vez a 48 public Thread thr ; // objeto hebra encapsulado 49 50 public Dormilona( String p_nombre, int p_vueltas, int p_siesta ) 51 { 52 siesta = p_siesta ; 53 vueltas = p_vueltas ; 54 thr = new Thread( this, p_nombre ) ; 55 } 56 57 //... ¦ creado October 4, 2013- p´gina 184 / 222 a ¤ ¥
  • 185. SCD (13-14). Seminario 2. Hebras en Java.. Ejemplo de un vector de hebras (2) El m´todo run contiene el c´digo que ejecutan todas las hebras: e o § 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 } ¦ 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 //... public void run() { try { Random random = new Random(); // crea generador de n´meros aleatorios u // dormir un numero de veces igual a ”vueltas” for ( int i=0 ; i < vueltas || vueltas == 0 ; i++ ) { // imprimir nombre System.out.println( "Vuelta no."+i+", de " +thr.getName()); // duerme un tiempo aleatorio entre 0 y siesta-1 milisegundos if ( siesta > 0 ) Thread.sleep( random.nextInt( siesta ) ); } } catch( InterruptedException e ) { System.out.println( Thread.currentThread().getName()+ ": me fastidiaron la siesta!"); } } // fin run // fin de la clase Dormilona Ejemplo de un vector de hebras (4) El m´todo main lee los par´metros. e a § class Principal2 { public static void main( String[] args ) { try { if ( args.length < 3 ) { System.out.println( "falta num_hebras, t_max_siesta, vueltas" ); System.exit( 1 ); } int nHebras = Integer.parseInt( args[0] ); int siesta = Integer.parseInt( args[1] ); int vueltas = Integer.parseInt( args[2] ); ¦ System.out.println( "nHebras = "+nHebras+", vueltas = "+vueltas+ ", tsiesta = "+siesta ); //.... Ejemplo de un vector de hebras (5) Finalmente, se crean las hebras en el vector vhd y se lanzan todas § //.... Dormilona[] vhd = new Dormilona[nHebras] ; // crea vector de hebras creado October 4, 2013- p´gina 185 / 222 a ¤ ¥ ¤ ¥ ¤
  • 186. SCD (13-14). Seminario 2. Hebras en Java.. 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 } 115 } ¦ for ( int i =0 ; i < nHebras ; i++ ) { String nombre = "Dormilona no."+i ; vhd[i] = new Dormilona(nombre,vueltas,siesta); // crear hebra i. vhd[i].thr.start(); // comienza su ejec. } // la hebra principal duerme durante un segundo Thread.sleep( 1000 ); System.out.println( "main(): he terminado de dormir" ); // esperar a que terminen todas las hebras creadas for( int i = 0 ; i < nHebras ; i++ ) vhd[i].thr.join(); } catch( InterruptedException e ) { System.out.println( "main(): me fastidiaron la siesta!" ); } 8.5 ¥ Interacci´n entre hebras Java. Objetos compartidos o Interacci´n entre hebras Java. Objetos compartidos o • En muchos casos, las hebras de un programa concurrente en Java han de interactuar para comunicarse y cooperar. • La forma m´s simple en la que m´ltiples hebras Java pueden interactuar es mediante un objeto cuyos a u m´todos pueden ser invocados por un conjunto de hebras. Invocando los m´todos de este objeto e e compartido las hebras modifican el estado del mismo. • Dos hebras se pueden comunicar si una escribe el estado del objeto compartido y otra lo lee. Asimismo, la cooperaci´n entre hebras se puede llevar a cabo mediante la actualizaci´n de alguna informaci´n o o o encapsulada en un objeto compartido. • La ejecuci´n concurrente entre hebras Java supone un entrelazamiento arbitrario de instrucciones o at´micas que puede dar lugar a estados incorrectos de los objetos compartidos por varias hebras. o 8.5.1 Implementando exclusi´n mutua en Java. C´digo y m´todos sincronizados. o o e Exclusi´n mutua en Java. C´digo y m´todos sincronizados. o o e • En Java, cda objeto tiene un cerrojo interno asociado. El cerrojo de un objeto solamente puede ser adquirido por una sola hebra en cada momento. • El cualificador synchronized sirve para hacer que un bloque de c´digo o un m´todo sea protegido o e por el cerrojo del objeto. creado October 4, 2013- p´gina 186 / 222 a
  • 187. SCD (13-14). Seminario 2. Hebras en Java.. • Para ejecutar un bloque o un m´todo sincronizado, las hebras deben adquirir el cerrojo del objeto, e debiendo esperar si el cerrojo ha sido ya adquirido por otra hebra. • Si obj es una referencia a un objeto (de cualquier clase), la siguiente construcci´n hace que las hebras o tengan que adquirir el cerrojo del objeto para ejecutar el bloque de c´digo sincronizado. o § ¦ synchronized( obj ) { // bloque de codigo sincronizado } ¥ Si todas las secciones cr´ ıticas est´n en el c´digo de un unico objeto, podremos utilizar this para referenciar a o ´ al objeto cuyo cerrojo vamos a utilizar: § ¦ synchronized( this ) { // bloque de codigo sincronizado } Podemos hacer que el cuerpo entero de un m´todo sea c´digo sincronizado: e o tipo metodo( ... ) { synchronized( this ) { // codigo del metodo sincronizado } } La siguiente construcci´n es equivalente a la anterior: o ¤ synchronized tipo metodo( ... ) { // codigo del metodo sincronizado } 8.5.2 ¤ ¥ § ¦ ¤ ¥ § ¦ ¤ ¥ Ejemplo: C´lculo de m´ltiplos a u Clase contador de n´mero de m´ltiplos u u Programa multihebra para calcular el n´mero de m´ltiplos de 2 y 3 entre 1 y 1000 ambos incluidos. u u • Una hebra contar´ m´ltiplos de 2 y otra de 3. a u • Para llevar la cuenta se crea un unico objeto compartido de la clase Contador, que encapsula un valor ´ entero. • La clase Contador incluye un m´todo para incrementarlo y otro para obtener el valor. e • El uso compartido requiere usar esas m´todos en exclusi´n mutua. e o creado October 4, 2013- p´gina 187 / 222 a
  • 188. SCD (13-14). Seminario 2. Hebras en Java.. 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 Clase contador de n´mero de m´ltiplos u u La clase Contador puede declararse as´ ı: § class Contador { private long valor; public Contador( long inicial ) { valor = inicial ; } void retrasoOcupado() // ocupa la CPU durante cierto tiempo { long tmp = 0 ; for( int i = 0 ; i < 100000 ; i++ ) tmp = tmp*i-tmp+i ; } public synchronized void incrementa () // incrementa valor en 1 { long aux = valor ; // hace copia local del valor actual retrasoOcupado() ; // permite entrelazado cuando no se hace en EM valor = aux+1 ; // escribe el valor compartido (incrementado) } public synchronized long getvalor () // devuelve el valor actual { return valor; } } ¦ Hebras que cuentan los m´ltiplos u Cada una de las hebras incrementa el contador cuando encuentra un m´ltiplo: u § class Hebra implements Runnable { int numero ; // cuenta m´ltiplos de este n´mero u u public Thread thr ; // objeto encapsulado private Contador cont; // contador de n´mero de m´ltiplos u u 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 } ¦ ¤ ¥ ¤ public Hebra( String nombre, int p_numero, Contador p_contador ) { numero = p_numero; cont = p_contador; thr = new Thread( this, nombre ); } public void run () { for ( int i = 1 ; i <= 1000 ; i++ ) if (i % numero == 0) cont.incrementa(); } ¥ ¿ que pasar´ si los dos m´todos de Contador no fueran synchronized ? ıa e Programa principal Lanza dos hebras e imprime la cuenta calculada y la correcta: § 38 class Multiplos 39 { public static void main( String[] args ) ¤ creado October 4, 2013- p´gina 188 / 222 a
  • 189. SCD (13-14). Seminario 2. Hebras en Java.. 40 { try 41 { Contador contH = new Contador(0); // contador usado por la hebras 42 Hebra[] vc = new Hebra[2] ; 43 vc[0] = new Hebra( "Contador2 ", 2, contH); 44 vc[1] = new Hebra( "Contador3 ", 3, contH); 45 vc[0].thr.start(); vc[1].thr.start(); // lanza hebras 46 vc[0].thr.join(); vc[1].thr.join(); // espera terminaci´n o 47 System.out.println("Resultado hebras : "+contH.getvalor()); 48 long contV = 0 ; // contador de verificacion 49 for ( int i = 1 ; i <= 1000 ; i++ ) 50 { if ( i % 2 == 0 ) contV = contV + 1 ; 51 if ( i % 3 == 0 ) contV = contV + 1 ; 52 } 53 System.out.println("Resultado correcto: " + contV); 54 } 55 catch (InterruptedException e) 56 { System.out.println ("ha ocurrido una excepcion."); 57 } 58 } 59 } ¦ 8.6 ¥ Compilando y ejecutando programas Java Compilar programas Java Los programas fuente se encuentran en archivos de extensi´n .java. Cada uno de ellos contendr´ una o o a mas definiciones de clases. Para compilar un fuente java (en un archivo principal.java, por ejemplo), hay que escribir: § javac principal.java ¦ Si el programa principal hace menci´n a clases definidas en otros archivos, el compilador intentar´ o a compilarlos tambi´n, aunque se podr´ hacer manualmente antes: e ıa § javac otro1.java javac otro2.java javac .... ¦ ¤ ¥ ¤ ¥ esto generar´ un archivo objeto (con bytecode) por cada clase definida en principal.java o en los otros a archivos. Ejecutar programas Java Los archivos con bytecode tienen el nombre de la clase y la extensi´n .class. o Una de las clases compiladas debe contener el m´todo principal (main), y lo usual (aunque no necesario) e es que dicha clase se llame igual que el fuente que lo contiene (en este caso principal). Si esto ocurre, el programa se ejecuta con la orden: § java principal ¦ creado October 4, 2013- p´gina 189 / 222 a ¤ ¥
  • 190. SCD (13-14). Pr´ctica 2. Programaci´n de monitores con hebras Java.. a o para poder encontrar los archivos binarios javac y java hay que asignar la variable de entorno PATH, en las aulas: § export PATH=/fenix/depar/lsi/java/jdk1.5.0linux/bin:.:${PATH} ¦ creado October 4, 2013- p´gina 190 / 222 a ¤ ¥
  • 191. Chapter 9 Pr´ctica 2. Programaci´n de monitores con a o hebras Java. 9.1 Objetivos Objetivos • Conocer c´mo construir monitores en Java, tanto usando la API para manejo de hebras Java, como o usando un conjunto de clases (el paquete monitor) que permite programar monitores siguiendo la misma sem´ntica de los monitores de Hoare. a • Conocer varios problemas sencillos de sincronizaci´n y su soluci´n basada en monitores en el lenguaje o o Java: ◾ Dise˜ar una soluci´n al problema del productor-consumidor con buffer acotado basada en monin o tores e implementarla con un programa Java multihebra, usando el paquete monitor. ◾ Dise˜ar una soluci´n al problema de los fumadores, visto en la pr´ctica 1, basada en monitores n o a e implementarla con un programa Java multihebra, usando el paquete monitor. 9.2 9.2.1 ◾ Dise˜ar e implementar una soluci´n al problema del barbero durmiente usando el paquete n o monitor. Implementaci´n de monitores nativos de Java o Monitores como Clases en Java Monitores como Clases en Java Para construir un monitor en Java, creamos una clase con sus m´todos sincronizados. De esta forma solamente e una hebra podr´ ejecutar en cada momento un m´todo del objeto. a e El siguiente ejemplo muestra un monitor que implementa un contador m´s general que el visto en el seminario: a § class Contador { private volatile int actual; // monitor contador 191 ¤
  • 192. SCD (13-14). Pr´ctica 2. Programaci´n de monitores con hebras Java.. a o public Contador( int inicial ) { actual = inicial ; } public synchronized void inc() { actual++ ; } public synchronized void dec() { actual-- ; } public synchronized int valor() { return actual ; } ¦ } 9.2.2 ¥ M´todos de espera y notificaci´n. e o M´todos de espera y notificaci´n (1) e o • En Java no existe el concepto de variable condici´n. Podr´ o ıamos decir que cada monitor en Java tiene una unica variable condici´n an´nima. ´ o o • Los monitores basados en la biblioteca est´ndar de Java implementan una versi´n restringida de la a o sem´ntica Se˜alar y Continuar (SC). a n • Los mecanismos de espera y notificaci´n se realizan con tres m´todos de la clase Object (los tienen o e impl´ ıcitamente todas las clases): wait, notify y notifyAll. • Estos m´todos solamente pueden ser llamados por una hebra cuando ´sta posee el cerrojo del objeto, e e es decir, desde un bloque o un m´todo sincronizado (protegido con synchronized). e M´todos de espera y notificaci´n (2) e o wait() Provoca que la hebra actual se bloquee y sea colocada en una cola de espera asociada al objeto monitor. El cerrojo del objeto es liberado para que otras hebras puedan ejecutar m´todos del objeto. Otros cerrojos e pose´ ıdos por la hebra suspendida son retenidos por esta. notify() Provoca que, si hay alguna hebra bloqueada en wait, se escoja una cualquiera de forma arbitraria, y se saque de la cola de wait pasando esta al estado preparado. La hebra que invoc´ notify seguir´ ejecut´ndose o a a dentro del monitor. notifyAll() Produce el mismo resultado que una llamada a notify por cada hebra bloqueada en la cola de wait: todas las hebras bloqueadas pasan al estado preparado. creado October 4, 2013- p´gina 192 / 222 a
  • 193. SCD (13-14). Pr´ctica 2. Programaci´n de monitores con hebras Java.. a o M´todos de espera y notificaci´n (3) e o La hebra se˜alada deber´ adquirir el cerrojo del objeto para poder ejecutarse. n a • Esto significar´ esperar al menos hasta que la hebra que invoc´ notify libere el cerrojo, bien por la a o ejecuci´n de una llamada a wait, o bien por la salida del monitor. o La hebra se˜alada no tiene prioridad alguna para ejecutarse en el monitor. n • Podr´ ocurrir que, antes de que la hebra se˜alada pueda volver a ejecutarse, otra hebra adquiera el ıa n cerrojo del monitor. Inconvenientes de los monitores nativos de Java • Cola de espera ´nica: como s´lo hay una cola de espera por objeto, todas las hebras que esperan a u o que se den diferentes condiciones deben esperar en el mismo conjunto de espera. Esto permite que una llamada a notify() despierte a una hebra que espera una condici´n diferente a la que realmente o se notific´, incluso aunque existan hebras esperando la condici´n que realmente se pretend´ notificar. o o ıa La soluci´n para esta restricci´n suele consistir en: o o ◾ Sustituir algunas o todas las llamadas a notify por llamadas a notifyAll. ◾ Poner las llamadas a wait en un bucle de espera activa: § while ( not ¦ condicion_logica_desbloqueo ) { wait() ; } ¤ ¥ • No hay reanudaci´n inmediata de hebra se˜alada: esto se debe a la sem´ntica SC que se sigue y o n a es la segunda raz´n del uso de incluir las llamadas a wait en bucles de espera activa. o 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 Ejemplo: Productor-Consumidor con buffer limitado Monitor que implementa un buffer acotado para m´ltiples productores y consumidores: u § class Buffer { private int numSlots = 0, cont = 0; private double[] buffer = null; public Buffer( int p_numSlots ) { numSlots = p_numSlots ; buffer = new double[numSlots] ; } public synchronized void depositar( double valor ) throws InterruptedException { while( cont == numSlots ) wait(); buffer[cont] = valor; cont++; notifyAll(); } public synchronized double extraer() throws InterruptedException { double valor; while( cont == 0 ) wait() ; cont--; valor = buffer[cont] ; notifyAll(); return valor; } } ¦ creado October 4, 2013- p´gina 193 / 222 a ¤ ¥
  • 194. SCD (13-14). Pr´ctica 2. Programaci´n de monitores con hebras Java.. a o 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 Productor-Consumidor: hebras consumidoras § class Consumidor implements Runnable { private Buffer bb ; int veces; int numC ; Thread thr ; public Consumidor( Buffer pbb, int pveces, int pnumC ) { bb = pbb; veces = pveces; numC = pnumC ; thr = new Thread(this,"consumidor "+numC); } public void run() { try { for( int i=0 ; i<veces ; i++ ) { double item = bb.extraer (); System.out.println(thr.getName()+", consumiendo "+item); } } catch( Exception e ) { System.err.println("Excepcion en main: " + e); } } } ¦ Productor-Consumidor: hebras productoras § class Productor implements Runnable { private Buffer bb ; int veces; int numP ; Thread thr ; public Productor( Buffer pbb, int pveces, int pnumP ) { bb = pbb; veces = pveces; numP = pnumP ; thr = new Thread(this,"productor "+numP); } public void run() { try { double item = 100*numP ; for( int i=0 ; i<veces ; i++ ) { System.out.println(thr.getName()+", produciendo " + item); bb.depositar( item++ ); } } catch( Exception e ) { System.err.println("Excepcion en main: " + e); } } creado October 4, 2013- p´gina 194 / 222 a ¤ ¥ ¤
  • 195. SCD (13-14). Pr´ctica 2. Programaci´n de monitores con hebras Java.. a o 45 } ¦ ¥ 9.3 Implementaci´n en Java de monitores estilo Hoare o Implementaci´n en Java de monitores estilo Hoare o • Se ha desarrollado una biblioteca de clases Java (paquete monitor) que soporta la sem´ntica de a monitores estilo Hoare. • Permite definir m´ltiples colas de condici´n y un signal supone la reactivaci´n inmediata del proceso u o o se˜alado (sem´ntica Se˜alar y espera Urgente, SU). n a n • La documentaci´n y el c´digo de las clases est´n disponibles en: o o a http://www.engr.mun.ca/ theo/Misc/monitors/monitors.html • Para definir una clase monitor espec´ ıfica se debe definir una extensi´n de la clase AbstractMonitor. o Exclusi´n mutua y uso del paquete monitor o Para garantizar la exclusi´n mutua en el acceso a los m´todos del monitor, se han de invocar los siguientes o e m´todos de la clase AbstractMonitor: e • enter(): para entrar al monitor, se invoca al comienzo del cuerpo del m´todo. e • leave(): para abandonar el monitor, se invoca al final del cuerpo (aunque cualquier return debe ir despu´s). e Uso del paquete • Es conveniente que el directorio monitor, conteniendo los archivos .java con las clases Java de dicho paquete, se encuentre colgando del mismo directorio donde se trabaje con los programas Java que usen el paquete monitor. • En caso contrario, habr´ que redefinir la variable de entorno CLASSPATH incluyendo la ruta de dicho ıa directorio. Ejemplo: Clase Monitor para contar los d´ ıas 3 4 5 6 7 8 9 Permite llevar un control de los d´ (considerados como grupos de 24 horas) dedicadas por todas las hebras ıas de usuario. § class Contador_Dias extends AbstractMonitor { private int num_horas = 0, num_dias = 0; public void nueva_hora() { enter() ; num_horas++; if ( num_horas == 24 ) { num_dias++; creado October 4, 2013- p´gina 195 / 222 a ¤
  • 196. SCD (13-14). Pr´ctica 2. Programaci´n de monitores con hebras Java.. a o 10 11 12 13 14 15 16 17 18 19 20 } ¦ num_horas=0; } leave() ; } public int obtener_dia( ) { enter() ; int valor=num_dias; leave() ; return valor; } ¥ Objetos condici´n del paquete monitor o Es posible utilizar varias colas de condici´n, declarando diversos objetos de una clase denominada Condition. o • Para crear un objeto condici´n, se invoca el m´todo makeCondition() de la clase AbstractMonitor. o e Ejemplo: § ¦ Condition puede_leer = makeCondition() ; ¤ ¥ La clase Condition proporciona m´todos de espera, notificaci´n y para consultar el estado de la cola de e o condici´n: o • void await(): tiene la misma sem´ntica que la primitiva wait() de los monitores estilo Hoare. a • void signal(): igual que la primitiva signal() de los monitores estilo Hoare. • int count(): devuelve el n´mero de hebras que esperan. u • boolean isEmpty(): indica si la cola de condici´n est´ vac´ (true) o no (false). o a ıa 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 Ejemplo: Monitor lectores-escritores (1) Con prioridad a las lecturas. § class MonitorLE extends AbstractMonitor { private int num_lectores = 0 ; private boolean escribiendo = false ; private Condition lectura = makeCondition(); private Condition escritura = makeCondition(); ¤ public void inicio_lectura() { enter(); if (escribiendo) lectura.await(); num_lectores++; lectura.signal(); leave(); } public void fin_lectura() creado October 4, 2013- p´gina 196 / 222 a
  • 197. 19 20 21 22 23 SCD (13-14). Pr´ctica 2. Programaci´n de monitores con hebras Java.. a o ¦ { enter(); num_lectores--; if (num_lectores==0) escritura.signal(); leave(); } ¥ Ejemplo: Monitor lectores-escritores (2) § 24 25 26 27 28 29 30 31 32 33 34 35 36 37 } ¦ ¤ public void inicio_escritura() { enter(); if (num_lectores>0 || escribiendo) escritura.await(); escribiendo=true; leave(); } public void fin_escritura() // prio. lect { enter(); escribiendo=false; if (lectura.isEmpty()) escritura.signal(); else lectura.signal(); leave(); } // fin clase monitor ”Lect Esc” Probl. lectores-escritores: Hebra Lectora. § class Lector implements Runnable { private MonitorLE monitorLE ; // objeto monitor l.e. compartido private int nveces ; // numero de veces que lee public Thread thr ; // objeto hebra encapsulado 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 } ¦ ¥ ¤ public Lector( MonitorLE p_monitorLE, int p_nveces, String nombre ) { monitorLE = p_monitorLE ; nveces = p_nveces ; thr = new Thread(this,nombre); } public void run() { for( int i = 0 ; i < nveces ; i++ ) { System.out.println( thr.getName()+": solicita lectura."); monitorLE.inicio_lectura(); System.out.println( thr.getName()+": leyendo."); aux.dormir_max( 1000 ) ; monitorLE.fin_lectura(); } } Probl. lectores-escritores: Hebra Escritora. ¥ creado October 4, 2013- p´gina 197 / 222 a
  • 198. SCD (13-14). Pr´ctica 2. Programaci´n de monitores con hebras Java.. a o § 74 class Escritor implements Runnable 75 { 76 private MonitorLE monitorLE ; // objeto monitor l.e. compartido 77 private int nveces ; // numero de veces que lee 78 public Thread thr ; // objeto hebra encapsulado 79 80 public Escritor( MonitorLE p_monitorLE, int p_nveces, String nombre ) 81 { monitorLE = p_monitorLE ; 82 nveces = p_nveces ; 83 thr = new Thread(this,nombre); 84 } 85 public void run() 86 { for( int i = 0 ; i < nveces ; i++ ) 87 { System.out.println( thr.getName()+": solicita escritura."); 88 monitorLE.inicio_escritura(); 89 System.out.println( thr.getName()+": escribiendo."); 90 aux.dormir_max( 1000 ); 91 monitorLE.fin_escritura (); 92 } 93 } 94 } ¦ ¤ ¥ Probl. lectores-escritores: clase auxiliar se ha usado el m´todo (est´tico) dormir_max de la clase aux. Este m´todo sirve para bloquear la hebra e a e que lo llama durante un tiempo aleatorio entre 0 y el n´mero m´ximo de milisegundos que se le pasa como u a par´metro. Se puede declarar como sigue: a § 39 class aux 40 { 41 static Random genAlea = new Random() ; 42 static void dormir_max( int milisecsMax ) 43 { try 44 { Thread.sleep( genAlea.nextInt( milisecsMax ) ) ; 45 } 46 catch( InterruptedException e ) 47 { System.err.println("sleep interumpido en ’aux.dormir_max()’"); 48 } 49 } 50 } ¦ 9.4 Productor-Consumidor con buffer limitado Ejercicio propuesto Obtener una versi´n de la clase Buffer, que se desarroll´ en una secci´n anterior para m´ltiples productores o o o u y consumidores, usando las clases vistas del paquete monitor. Documentaci´n para el portafolio o creado October 4, 2013- p´gina 198 / 222 a ¤ ¥
  • 199. SCD (13-14). Pr´ctica 2. Programaci´n de monitores con hebras Java.. a o Los alumnos redactar´n un documento donde se responda de forma razonada a cada uno de los siguientes a puntos: 1. Describe los cambios que has realizado sobre la clase Buffer vista anteriormente, indicando qu´ e objetos condici´n has usado y el prop´sito de cada uno. o o 2. Incluye el c´digo fuente completo de la soluci´n adoptada. o o 3. Incluye un listado de la salida del programa (para 2 productores, 2 consumidores, un buffer de tama˜o n 3 y 5 iteraciones por hebra. 9.5 El problema de los fumadores El problema de los fumadores Considerar un estanco en el que hay tres fumadores y un estanquero. Cada fumador continuamente l´ un ıa cigarro y se lo fuma. Para liar un cigarro, el fumador necesita tres ingredientes: tabaco, papel y cerillas. Uno de los fumadores tiene solamente papel, otro tiene solamente tabaco, y el otro tiene solamente cerillas. El estanquero tiene una cantidad infinita de los tres ingredientes. El estanquero coloca aleatoriamente dos ingredientes diferentes de los tres que se necesitan para hacer un cigarro, desbloquea al fumador que tiene el tercer ingrediente y despu´s se bloquea. El fumador desbloe queado toma los dos ingredientes del mostrador, desbloqueando al estanquero, l´ un cigarro y fuma durante ıa un tiempo. El estanquero, una vez desbloqueado, vuelve a poner dos ingredientes aleatorios en el mostrador, y se repite el ciclo. Ejercicio propuesto Escribir un programa Java que implemente el esquema de sincronizaci´n explicado. Se escribir´ una clase o a hebra Estanquero y otra Fumador, especificando en el constructor de esta ultima clase el ingrediente que ´ tiene el fumador. La interacci´n entre los fumadores y el estanquero ser´ resuelta mediante un monitor o a Estanco basado en el paquete monitor. Usar las plantillas que se incluyen abajo. Documentaci´n a entregar o Los alumnos redactar´n un documento donde se responda de forma razonada a cada uno de los siguientes a puntos: 1. Describe qu´ objetos condici´n has usado y el prop´sito de cada uno. e o o 2. Incluye el c´digo fuente completo de la soluci´n adoptada. o o 3. Incluye un listado de la salida del programa. Plantilla del monitor Estanco y la hebra Fumador § class Estanco extends AbstractMonitor { ... public void obtenerIngredientes( int miIngrediente ) { ... } creado October 4, 2013- p´gina 199 / 222 a ¤
  • 200. SCD (13-14). Pr´ctica 2. Programaci´n de monitores con hebras Java.. a o public void ponerIngredientes( int ingred1, int ingred2 ) { ... } public void esperarRecogidaIngredientes () { ... } } class Fumador implements Runnable { int miIngrediente; public Thread thr ; ... public Fumador( int miIngrediente, ... ) { ... } public void run() { while ( true ) { estanco.obtenerIngredientes( miIngrediente ); try { Thread.sleep (tiempo); } catch (InterruptedException e) { } } } } ¦ Plantilla de la hebra Estanquero § class Estanquero implements Runnable { public Thread thr ; ... public void run() { int ingrediente1, ingrediente2; while (true) { do { ingrediente1 = (int) (Math.random () * 3.0); ingrediente2 = (int) (Math.random () * 3.0); } while( ingrediente1 == ingrediente2 ); estanco.ponerIngredientes( ingrediente1, ingrediente2 ); estanco.esperarRecogidaIngredientes() ; } } } ¦ 9.6 El problema del barbero durmiente. El problema del barbero durmiente (1) El problema del barbero durmiente es representativo de cierto tipo de problemas reales: ilustra perfectamente la relaci´n de tipo cliente-servidor que a menudo aparece entre los procesos. o • Una barber´ tiene dos puertas y unas cuantas sillas. Los clientes entran por una puerta y salen por ıa otra. creado October 4, 2013- p´gina 200 / 222 a ¥ ¤ ¥
  • 201. SCD (13-14). Pr´ctica 2. Programaci´n de monitores con hebras Java.. a o • Solamente un cliente o el barbero pueden moverse por el local en cada momento. • El barbero continuamente sirve clientes, uno cada vez. Cuando no hay ning´n cliente en la barber´ u ıa, el barbero est´ durmiendo en su silla. a • Cuando un cliente entra en la barber´ y encuentra al barbero durmiendo, lo despierta, se sienta en ıa su silla, y espera a que el barbero termine de pelarlo. • Si el barbero est´ ocupado cuando un nuevo cliente entra, el cliente se sienta en una silla de la sala a de espera y espera a que el barbero lo despierte. El problema del barbero durmiente(2) • Cuando el barbero termina de pelar al cliente actual, lo despierta, abre la puerta de salida, y espera a que el cliente salga y cierre la puerta para pasar al siguiente cliente. • A continuaci´n, si hay clientes esperando, el barbero despierta a uno y espera a que se siente en la o silla para pelarlo. • Si no hay clientes esperando, el barbero se sienta en su silla y duerme hasta que llegue alg´n cliente u y lo despierte. Ejercicio propuesto Escribir un programa Java para el problema del barbero durmiente. Los clientes y el barbero son hebras, y la barber´ es un monitor que implementa la interacci´n entre ´stos. Los clientes llaman a cortarPelo para ıa o e obtener servicio del barbero, despert´ndolo o esperando a que termine con el cliente anterior. El barbero a llama a siguienteCliente para esperar la llegada de un nuevo cliente y servirlo. Cuando termina de pelar al cliente actual llama a finCliente, indic´ndole que puede salir de la barber´ y esperando a que a ıa lo haga para pasar al siguiente cliente. Usar las plantillas que se incluyen abajo. Documentaci´n para el portafolio o Los alumnos redactar´n un documento con lo siguiente: a 1. Descripci´n de los objetos condici´n usados y su prop´sito. o o o 2. C´digo fuente completo de la soluci´n. o o 3. Listado de la salida del programa. Plantilla del Monitor Barberia § class Barberia extends AbstractMonitor { ... public void cortarPelo () { ... } public void siguienteCliente () { ... } ¤ creado October 4, 2013- p´gina 201 / 222 a
  • 202. SCD (13-14). Seminario 3. Introducci´n al paso de mensajes con MPI.. o public void finCliente () { ... } } ¦ ¥ Plantilla de las hebras Cliente y Barbero § class Cliente implements Runnable { public Thread thr ; ... public void run () { while (true) { barberia.cortarPelo (); try { Thread.sleep (tiempo); } catch (InterruptedException e) { } } } } class Barbero implements Runnable { public Thread thr ; ... public void run () { while (true) { barberia.siguienteCliente (); try { Thread.sleep (tiempo); } catch (InterruptedException e) { } barberia.finCliente (); } } } ¦ creado October 4, 2013- p´gina 202 / 222 a ¤ ¥
  • 203. Chapter 10 Seminario 3. Introducci´n al paso de o mensajes con MPI. Introducci´n o • El objetivo de esta pr´ctica es familiarizar al alumno con el uso de la interfaz de paso de mensajes a MPI y la implementaci´n OpenMPI de esta interfaz. o • Se indicar´n los pasos necesarios para compilar y ejecutar programas usando OpenMPI. a • Se presentar´n las principales caracter´ a ısticas de MPI y algunas funciones b´sicas de comunicaci´n a o entre procesos. Enlaces para acceder a informaci´n complementaria o • Web oficial de OpenMPI. • Instalaci´n de OpenMPI en Linux. o • Ayuda para las funciones de MPI. • Tutorial de MPI. 203
  • 204. SCD (13-14). Seminario 3. Introducci´n al paso de mensajes con MPI.. o 10.1 Message Passing Interface (MPI) ¿Qu´ es MPI? e • MPI es un est´ndar de programaci´n paralela mediante paso de mensajes que permite crear programas a o portables y eficientes. • Proporciona un conjunto de funciones que pueden ser utilizadas en programas escritos en C, C++, Fortran y Ada. • MPI-2 contiene m´s de 150 funciones para paso de mensajes y operaciones complementarias (con a numerosos par´metros y variantes). a • Muchos programas paralelos se pueden construir usando un conjunto reducido de dichas funciones (hay 6 funciones b´sicas). a Modelo de Programaci´n en MPI o • El esquema de funcionamiento implica un n´mero fijo de procesos que se comunican mediante llamadas u a funciones de env´ y recepci´n de mensajes. ıo o • Se sigue como modelo b´sico el estilo SPMD (Single Program Multiple Data), en el que todos los a procesos ejecutan un mismo programa. • Tambi´n se permite seguir un modelo MPMD (Multiple Program Multiple Data), en el que cada proceso e puede ejecutar un programa diferente. • La creaci´n e inicializaci´n de procesos no est´ definida en el est´ndar, depende de la implementaci´n. o o a a o En OpenMPI ser´ algo as´ ıa ı: ¿ mpirun -np 4 -machinefile maquinas prog1 ◾ Comienza 4 copias del ejecutable prog1. ◾ El archivo maquinas define la asignaci´n de procesos a m´quinas. o a Aspectos de implementaci´n o • include “mpi.h ◾ Define constantes, tipos de datos y los prototipos de las funciones MPI. • Las funciones devuelven un c´digo de error: o ◾ MPI SUCCESS: Ejecuci´n correcta. o • MPI Status es una estructura que se obtiene cada vez que se completa la recepci´n de un mensaje. o Contiene 2 campos: ◾ status.MPI SOURCE: proceso fuente. creado October 4, 2013- p´gina 204 / 222 a
  • 205. SCD (13-14). Seminario 3. Introducci´n al paso de mensajes con MPI.. o ◾ status.MPI TAG: etiqueta del mensaje. • Tipos de datos b´sicos para los mensajes en MPI: MPI CHAR, MPI INT, MPI LONG, MPI UNSIGNED CHAR, a MPI UNSIGNED, MPI UNSIGNED LONG, MPI FLOAT, MPI DOUBLE, MPI LONG DOUBLE, etc. • Comunicador: es tanto un grupos de procesos como un contexto de comunicaci´n. Todas las funciones o de comunicaci´n necesitan como argumento un comunicador. o 10.2 Compilaci´n y ejecuci´n de programas MPI o o Compilaci´n y ejecuci´n de programas en OpenMPI o o OpenMPI es una implementaci´n portable y de c´digo abierto del est´ndar MPI-2, llevada a cabo por una o o a serie de instituciones de ambito tanto acad´mico y cient´ ´ e ıfico como industrial OpenMPI ofrece varios scripts necesarios para trabajar con programas aumentados con llamadas a funciones de MPI. Los m´s importantes son: a • mpicxx: para compilar y enlazar programas C++ que hagan uso de MPI. • mpirun: para ejecutar programas MPI. mpicxx puede utilizarse con las mismas opciones que el compilador de C/C++ usual, p.e.: • $ mpicxx -c ejemplo.c • $ mpicxx -o ejemplo ejemplo.o Compilaci´n y ejecuci´n de programas MPI o o La forma m´s usual de ejecutar un programa MPI es : a • $ mpirun -np 4 ejemplo • El argumento -np sirve para indicar cu´ntos procesos ejecutar´n el programa ejemplo. En este caso, a a se lanzar´n cuatro procesos ejemplo. a • Como no se indica nada m´s, OpenMPI lanzar´ dichos procesos en la m´quina local. a a a 10.3 Funciones MPI b´sicas a Funciones MPI b´sicas a Hay 6 funciones b´sicas en MPI: a • MPI Init: Inicializa el entorno de ejecuci´n de MPI. o • MPI Finalize: Finaliza el entorno de ejecuci´n de MPI. o u • MPI Comm size: Determina el n´mero de procesos de un comunicador. creado October 4, 2013- p´gina 205 / 222 a
  • 206. SCD (13-14). Seminario 3. Introducci´n al paso de mensajes con MPI.. o • MPI Comm rank: Determina el identificador del proceso en un comunicador. • MPI Send: Operaci´n b´sica para env´ de un mensaje. o a ıo • MPI Recv: Operaci´n b´sica para recepci´n de un mensaje. o a o Inicializar y finalizar un programa MPI § int MPI_Init (int *argc, char ***argv) ¦ ¤ ¥ • Llamado antes de cualquier otra funci´n MPI. o • Si se llama m´s de una vez durante la ejecuci´n da un error. a o • Los argumentos argc, argv son los argumentos de la l´ ınea de orden del programa. § int MPI_Finalize ( ) ¦ ¥ • Llamado al fin de la computaci´n. o • Realiza tareas de limpieza para finalizar el entorno de ejecuci´n o 10.3.1 ¤ Introducci´n a los comunicadores o Introducci´n a los comunicadores MPI o • Comunicador MPI = variable de tipo MPI Comm. • Un comunicador est´ constituido por: a ◾ Grupo de procesos: Subconjunto de procesos (pueden ser todos). ◾ Contexto de comunicaci´n: Ambito de paso de mensajes en el que se comunican dichos procesos. o ´ Un mensaje enviado en un contexto s´lo puede ser recibido en dicho contexto. o • Todas las funciones de comunicaci´n de MPI necesitan como argumento un comunicador. o creado October 4, 2013- p´gina 206 / 222 a
  • 207. SCD (13-14). Seminario 3. Introducci´n al paso de mensajes con MPI.. o Introducci´n a los comunicadores o • MPI COMM WORLD hace referencia al comunicador universal, un comunicador predefinido por MPI que incluye a todos los procesos de la aplicaci´n (es el comunicador por defecto). o • La identificaci´n de los procesos participantes en un comunicador es un´ o ıvoca: • Un proceso puede pertenecer a diferentes comunicadores. • Cada proceso tiene un identificador: desde 0 a P − 1 (P es el n´mero de procesos del comunicador). u • Mensajes destinados a diferentes contextos de comunicaci´n no interfieren entre s´ o ı. Funciones para obtener informaci´n o § int MPI_Comm_size ( MPI_Comm comm, int *size ) ¦ ¤ ¥ • size : n´mero de procesos que pertenecen al comunicador comm. u • Ej.: MPI Comm size ( MPI COMM WORLD, &size). § int MPI_Comm_rank ( MPI_Comm comm, int *rank ) ¦ • rank : Identificador del proceso llamador en comm. § Ejemplo: #include "mpi.h" #include <iostream> using namespace std; int main(int argc, char *argv[]){ int rank, size; MPI_Init(&argc, &argv); MPI_Comm_size(MPI_COMM_WORLD,&size); MPI_Comm_rank(MPI_COMM_WORLD,&rank); cout<<"Hola desde proc. " <<rank<<" de "<<size<<endl; MPI_Finalize(); return 0; } ¦ ¤ ¥ ¤§ mpicxx -o holamundo holamundo.c mpirun -np 4 holamundo Hola Hola Hola Hola ¦ desde desde desde desde proc. proc. proc. proc. 0 2 1 3 de de de de 4 4 4 4 ¤ ¥ ¥ creado October 4, 2013- p´gina 207 / 222 a
  • 208. SCD (13-14). Seminario 3. Introducci´n al paso de mensajes con MPI.. o 10.3.2 Funciones b´sicas de env´ y recepci´n de mensajes a ıo o Env´ y recepci´n de mensajes ıo o § int MPI_Send(void *buf, int count, MPI_Datatype datatype, int dest, int tag, MPI_Comm comm) ¦ • Env´ los datos (count elementos de tipo datatype almacenados a partir de buf) al proceso dest con la ıa etiqueta tag (entero >= 0) dentro del comunicador comm. • Presenta una sem´ntica bloqueante con buffer (retorna cuando copia mensaje en buffer). a § int MPI_Recv(void *buf, int count, MPI_Datatype datatype, int source, int tag, MPI_Comm comm, MPI_Status *status ) ¦ ¤ ¥ ¤ ¥ • Recibe mensaje de proceso source dentro del comunicador comm (sem´ntica bloqueante) y lo almacena en a posiciones contiguas desde buf. • Solo se recibe desde source con etiqueta tag, aunque existen argumentos comod´ MPI ANY SOURCE, ın: MPI ANY TAG. Env´ y recepci´n de mensajes (2) ıo o • Argumentos count y datatype: especifican la longitud del mensaje. • Objeto status : Estructura con campos MPI SOURCE y MPI TAG. ◾ Permite obtener informaci´n sobre el mensaje recibido. o ◾ Tambi´n permite obtener el tama˜o del mensaje recibido: e n § int MPI_Get_count(MPI_Status *status, MPI_Datatype dtype, int *count) ¦ Ejemplo: Programa para dos procesos § ¦ ¤ ¥ ¤ MPI_Init( &argc, &argv ); MPI_Comm_rank( MPI_COMM_WORLD, &rank ); MPI_Comm_size( MPI_COMM_WORLD, &size ); if (rank == 0) { value=100; MPI_Send (&value, 1, MPI_INT, 1, 0, MPI_COMM_WORLD );} else MPI_Recv ( &value, 1, MPI_INT, 0, 0, MPI_COMM_WORLD, &status ); MPI_Finalize( ); creado October 4, 2013- p´gina 208 / 222 a ¥
  • 209. SCD (13-14). Seminario 3. Introducci´n al paso de mensajes con MPI.. o Ejemplo: Difusi´n de mensaje en anillo de procesos o § int main(int argc, char *argv[]) { int rank, size,value; MPI_Status status; MPI_Init(&argc, &argv); MPI_Comm_rank(MPI_COMM_WORLD, &rank); MPI_Comm_size( MPI_COMM_WORLD, &size ); do { if (rank == 0) { scanf( "%d", &value ); MPI_Send( &value, 1, MPI_INT, rank+1, 0, MPI_COMM_WORLD ); } else { MPI_Recv( &value, 1, MPI_INT, rank-1, 0, MPI_COMM_WORLD, &status ); if (rank < size-1) MPI_Send( &value, 1, MPI_INT, rank+1, 0, MPI_COMM_WORLD );} cout<< "Soy el proceso "<<rank<<" y he recibido "<<value<<endl; } while (value >= 0); MPI_Finalize(); return 0; } ¦ 10.4 Paso de mensajes s´ ıncrono en MPI Env´ en modo s´ ıo ıncrono En MPI existe una funci´n de env´ bloqueante sin buffer (env´ s´ o ıo ıo ıncrono): § int MPI_Ssend(void* buf, int count, MPI_Datatype datatype, int dest, int tag, MPI_Comm comm) ¦ • Presenta los mismos argumentos que MPI Send. • La operaci´n de env´ finalizar´ solo cuando el correspondiente Recv sea invocado y el receptor haya o ıo a comenzado a recibir el mensaje. • Cuando MPI Ssend devuelve el control, la zona de memoria que alberga el dato podr´ ser reutilizada a y el receptor habr´ alcanzado el punto de su ejecuci´n que corresponde a la llamada de la funci´n de a o o recepci´n. o • Si la correspondiente operaci´n de recepci´n usada es bloqueante (MPI Recv, por ejemplo), la o o sem´ntica del paso de mensajes es puramente s´ a ıncrona (existe una cita entre emisor y receptor). Ejemplo: Intercambio s´ ıncrono entre pares de procesos creado October 4, 2013- p´gina 209 / 222 a ¤ ¥ ¤ ¥
  • 210. SCD (13-14). Seminario 3. Introducci´n al paso de mensajes con MPI.. o § int main(int argc, char *argv[]) { int rank, size, mivalor, valor; MPI_Status status; MPI_Init(&argc, &argv); MPI_Comm_rank(MPI_COMM_WORLD, &rank); MPI_Comm_size( MPI_COMM_WORLD, &size ); mivalor=rank*(rank+1); if (rank %2 == 0) { // El orden de las operaciones es importante MPI_Ssend( &mivalor, 1, MPI_INT, rank+1, 0, MPI_COMM_WORLD ); MPI_Recv( &valor, 1, MPI_INT, rank+1, 0, MPI_COMM_WORLD, &status );} else { MPI_Recv( &valor, 1, MPI_INT, rank-1, 0, MPI_COMM_WORLD, &status ); MPI_Ssend( &mivalor, 1, MPI_INT, rank-1, 0, MPI_COMM_WORLD );} cout<< "Soy el proceso "<<rank<<" y he recibido "<<valor<<endl; MPI_Finalize(); return 0; } ¦ 10.5 Comunicaci´n no bloqueante o Comunicaci´n no bloqueante o • Las operaciones de comunicaci´n vistas anteriormente son bloqueantes. o ◾ Incluso MPI Send puede causar el bloqueo del emisor si la implementaci´n limita en exceso el o tama˜o del buffer y se env´ mensajes muy largos. n ıan • Se necesitan operaciones de comunicaci´n no bloqueantes o ◾ Sondeo de mensajes. Comunicaci´n As´ o ıncrona: ▸ MPI Iprobe: Chequeo no bloqueante para un mensaje. ▸ MPI Probe: Chequeo bloqueante para un mensaje. ◾ Env´ ıo-Recepci´n no bloqueantes sin buffer: o ▸ ▸ ▸ ▸ MPI MPI MPI MPI Isend: Inicia env´ pero retorna antes de copiar en buffer. ıo Irecv: Inicia recepci´n pero retorna antes de recibir. o Test: Chequea si la operaci´n no bloqueante ha finalizado. o Wait: Bloquea hasta que acabe la operaci´n no bloqueante. o Comunicaci´n as´ o ıncrona El acceso no estructurado a un recurso compartido requiere comprobar la existencia de mensajes sin recibirlos. creado October 4, 2013- p´gina 210 / 222 a ¤ ¥
  • 211. SCD (13-14). Seminario 3. Introducci´n al paso de mensajes con MPI.. o § int MPI_Iprobe(int source, int tag, MPI_Comm comm, int *flag, MPI_Status *status) ¦ • No bloquea si no hay mensajes. Si hay mensaje, se recibe con MPI Recv. ¤ § int MPI_Probe(int source, int tag, MPI_Comm comm, MPI_Status *status) ¦ • Retorna s´lo cuando hay alg´n mensaje que encaje con los argumentos. o u ¤ • Si (flag ¿ 0), eso indica que hay un mensaje pendiente que encaja con (source, tag, comm). • El argumento status permite obtener m´s informaci´n sobre el mensaje pendiente de recepci´n. a o o • Permite esperar la llegada de un mensaje sin conocer su procedencia, etiqueta o tama˜o. n Ejemplo: Sondeo continuo de varias fuentes desconocidas § int rank, size, flag, buf, src,tag; ... MPI_Comm_rank(MPI_COMM_WORLD, &rank); MPI_Comm_size( MPI_COMM_WORLD, &size ); if (rank == 0) { int contador=0; while (contador<10*(size-1)){ MPI_Iprobe(MPI_ANY_SOURCE,MPI_ANY_TAG,MPI_COMM_WORLD, &flag, &status); if (flag>0){ MPI_Recv(&buf, 1, MPI_INT, MPI_ANY_SOURCE, MPI_ANY_TAG, MPI_COMM_WORLD, &status ); src=status.MPI_SOURCE; tag=status.MPI_TAG; cout<<"Mensaje de "<<src<<" con tag= "<<tag<<endl; contador++;} } cout<< "Total de mensajes recibidos: "<< contador<<endl; } else for (int i=0; i<10; i++) MPI_Send( &buf, 1, MPI_INT, 0, i, MPI_COMM_WORLD ); ... ¦ Ejemplo: Recepci´n de mensaje con tama˜o y fuente desconocidos o n § int count, *buf, source; // Me bloqueo hasta que se detecte un mensaje MPI_Probe (MPI_ANY_SOURCE, 0,comm, &status); // Se averigua el tama˜o y el proceso emisor del mensaje n MPI_Get_count(status, MPI_INT, &count); source= status.MPI_SOURCE; // Se reserva memoria para recibir el mensaje buf=malloc(count*sizeof(int)); // Se recibe el mensaje MPI_Recv(buf, count, MPI_INT, source, 0, comm, &status); ¦ creado October 4, 2013- p´gina 211 / 222 a ¥ ¥ ¤ ¥ ¤ ¥
  • 212. SCD (13-14). Seminario 3. Introducci´n al paso de mensajes con MPI.. o Operaciones no bloqueantes § int MPI_Isend(void* buf, int count, MPI_Datatype datatype, int dest, int tag, MPI_Comm comm, MPI_Request *request) int MPI_Irecv(void* buf, int count, MPI_Datatype datatype, int source, int tag, MPI_Comm comm, MPI_Request *request) ¦ ¤ ¥ Los argumentos son similares a MPI Send excepto: • Argumento request: Identifica operaci´n cuyo estado se pretende consultar o se espera que finalice. o § ¦ • No incluye argumento status: Se puede obtener con otras 2 funciones de chequeo de estado. int MPI_Request_free(MPI_Request *request) ¥ • Liberaci´n expl´ o ıcita de un objeto request Operaciones no bloqueantes. Chequeo de estado § int MPI_Test(MPI_Request *request, int *flag, MPI_Status *status) ¦ § ¦ ¤ • Si flag > 0 entonces la operaci´n identificada ha finalizado, libera request e inicializa status. o int MPI_Wait(MPI_Request *request, MPI_Status *status) ¤ ¥ ¤ ¥ • Produce bloqueo hasta que la operaci´n chequeada finaliza (es segura). o Es posible conectar operaciones no bloqueantes con sus contrapartes bloqueantes. Ejemplo: Intercambio de mensajes usando operaciones no bloqueantes § int main(int argc, char *argv[]) { int rank, size, vecino, mivalor, valor; MPI_Status status; MPI_Request request_send,request_recv; MPI_Init(&argc, &argv); MPI_Comm_rank(MPI_COMM_WORLD, &rank); MPI_Comm_size( MPI_COMM_WORLD, &size ); mivalor=rank*(rank+1); if (rank %2 == 0) vecino=rank+1; else vecino=rank-1; // Las siguientes operaciones pueden aparecer en cualquier orden MPI_Irecv(&valor,1,MPI_INT,vecino,0,MPI_COMM_WORLD,&request_recv); MPI_Isend(&mivalor,1,MPI_INT,vecino,0,MPI_COMM_WORLD,&request_send); ... // Aqu´ se puede hacer algo que no use mivalor ni altere valor ı creado October 4, 2013- p´gina 212 / 222 a ¤
  • 213. SCD (13-14). Pr´ctica 3. Implementaci´n de algoritmos distribuidos con MPI.. a o MPI_Wait(&request_send,&status); //Me bloqueo hasta que sea seguro MPI_Wait(&request_recv,&status); cout<< "Soy el proceso "<<rank<<" y he recibido "<<valor<<endl; MPI_Finalize(); return 0; } ¦ creado October 4, 2013- p´gina 213 / 222 a ¥
  • 214. SCD (13-14). Pr´ctica 3. Implementaci´n de algoritmos distribuidos con MPI.. a o creado October 4, 2013- p´gina 214 / 222 a
  • 215. Chapter 11 Pr´ctica 3. Implementaci´n de algoritmos a o distribuidos con MPI. 11.1 Objetivos Objetivos • El objetivo general es iniciarse en la programaci´n de algoritmos distribuidos. o • Conocer varios problemas sencillos de sincronizaci´n y su soluci´n distribuida mediante el uso de la o o interfaz de paso de mensajes MPI: ◾ Dise˜ar una soluci´n distribuida al problema del productor-consumidor con buffer acotado para n o varios productores y varios consumidores, usando MPI. 11.2 11.2.1 ◾ Dise˜ar diversas soluciones al problema de la cena de los fil´sofos usando MPI. n o Productor-Consumidor con buffer acotado en MPI Aproximaci´n inicial en MPI o Aproximaci´n inicial en MPI o • Supongamos que disponemos de una versi´n distribuida del problema del productor-consumidor que usa tres o procesos y la interfaz de paso de mensajes MPI. Para ello, tendremos un proceso productor (proceso 0 del comunicador universal) que producir´ datos, un proceso Buffer (proceso 1) que gestionar´ el intercambio de a a datos y un proceso consumidor que procesar´ los datos (proceso 2). El esquema de comunicaci´n entre estos a o procesos se muestra a continuaci´n: o 215
  • 216. SCD (13-14). Pr´ctica 3. Implementaci´n de algoritmos distribuidos con MPI.. a o • El proceso Productor se encarga de ir generando enteros comenzando por el 0 y envi´rselos al proceso a Buffer. El proceso Consumidor env´ peticiones al proceso Buffer, recibe los enteros de Buffer, los ıa imprime por pantalla y calcula su ra´ cuadrada. ız • El proceso Buffer deber´ atender las peticiones de ambos procesos (Productor y Consumidor). ıa Aproximaci´n inicial. C´digo usando MPI o o • Una aproximaci´n inicial al problema se muestra en el siguiente c´digo MPI para tres procesos, que o o modela la interacci´n de los mismos de una forma incorrecta al forzar una excesiva sincronizaci´n entre o o productor y consumidor. § #include "mpi.h" ... #define Productor 0 #define Buffer 1 #define Consumidor 2 #define ITERS 20 ... int main(int argc, char *argv[]) { int rank,size; MPI_Init( &argc, &argv ); MPI_Comm_rank( MPI_COMM_WORLD, &rank ); MPI_Comm_size( MPI_COMM_WORLD, &size ); if (rank == Productor) productor(); else if (rank==Buffer) buffer(); else consumidor(); MPI_Finalize( ); return 0; } ¦ ¤ ¥ Proceso Productor, Consumidor y Buffer § void productor(){ for (unsigned int i=0;i<ITERS;i++){ cout<< "Productor produce valor "<<i<<endl<<flush; MPI_Ssend( &i, 1, MPI_INT, Buffer, 0, MPI_COMM_WORLD );} } ¦ § void consumidor(){ int value,peticion=1; float raiz; MPI_Status status; for (unsigned int i=0;i<ITERS;i++){ MPI_Ssend(&peticion,1, MPI_INT, Buffer, 0, MPI_COMM_WORLD); MPI_Recv(&value, 1, MPI_INT, Buffer, 0, MPI_COMM_WORLD,&status ); cout<< "Consumidor recibe valor "<<value<<" de Buffer "<<endl<<flush; raiz=sqrt(value);} } ¦ creado October 4, 2013- p´gina 216 / 222 a ¤ ¥ ¤ ¥
  • 217. SCD (13-14). Pr´ctica 3. Implementaci´n de algoritmos distribuidos con MPI.. a o § void buffer(){ int value,peticion; MPI_Status status; for (unsigned int i=0;i<ITERS;i++){ MPI_Recv(&value, 1, MPI_INT, Productor, 0, MPI_COMM_WORLD,&status ); MPI_Recv(&peticion, 1, MPI_INT, Consumidor, 0, MPI_COMM_WORLD,&status ); MPI_Ssend( &value, 1, MPI_INT, Consumidor, 0, MPI_COMM_WORLD); cout<< "Buffer envia valor "<< value << " a Consumidor "<<endl<<flush;} } ¦ 11.2.2 ¤ ¥ Soluci´n con selecci´n no determinista o o Soluci´n con selecci´n no determinista o o • Se debe permitir que el productor pueda enviar TAM datos sin tener que interrumpirse, y que el consumidor no se retrase cuando haya datos almacenados en el proceso buffer. • Una forma de corregir dicho c´digo consiste en usar una sentencia de selecci´n no determinista de o o ´rdenes con guarda en el proceso Buffer que permita cierta asincron´ entre productor y consumidor o ıa en funci´n del tama˜o del buffer temporal (TAM). o n • En MPI, no hay ninguna sentencia de selecci´n no determinista de ´rdenes con guarda, pero es f´cil o o a emularla con las funciones de sondeo MPI Probe y/o MPI Iprobe. Proceso Buffer con selecci´n no determinista o § void buffer(){ int value[TAM], peticion, pos=0,rama; MPI_Status status; for (unsigned int i=0;i<ITERS*2;i++){ if (pos==0) rama=0; //El consumidor no puede consumir else if (pos==TAM) rama=1; // El productor no puede producir else{ //Ambas guardas son ciertas MPI_Probe(MPI_ANY_SOURCE,MPI_ANY_TAG, MPI_COMM_WORLD,&status); if (status.MPI_SOURCE==Productor) rama =0; else rama=1; } switch(rama){ case 0: MPI_Recv(&value[pos],1,MPI_INT, Productor,0,MPI_COMM_WORLD,&status); cout<< "Buffer recibe "<< value[pos] << " de Prod. "<<endl<<flush; pos++; break; case 1: MPI_Recv(&peticion,1,MPI_INT,Consumidor,0,MPI_COMM_WORLD,&status); MPI_Ssend(&value[pos-1],1,MPI_INT,Cons., 0, MPI_COMM_WORLD); cout<< "Buffer envia "<< value[pos-1] << " a Cons."<<endl<<flush; pos--; break;} } } ¦ creado October 4, 2013- p´gina 217 / 222 a ¤ ¥
  • 218. SCD (13-14). Pr´ctica 3. Implementaci´n de algoritmos distribuidos con MPI.. a o Ejercicio propuesto Extender el programa MPI anteriormente presentado que implementa el productor-consumidor con buffer acotado (los fuentes del programa se proporcionan junto con el gui´n de pr´cticas) para que el proceso o a buffer d´ servicio a 5 productores y 4 consumidores. Para ello, se lanzar´n 10 procesos y asumiremos e a que los procesos 0 . . . 4 son productores, el proceso Buffer es el proceso 5 y el resto de procesos en el comunicador universal (6 . . . 9) son consumidores. Documentaci´n para el portafolios o Los alumnos redactar´n un documento donde se responda de forma razonada a cada uno de los siguientes a puntos: 1. Describe qu´ cambios has realizado sobre el programa de partida y el prop´sito de dichos cambios. e o 2. Incluye el c´digo fuente completo de la soluci´n adoptada. o o 3. Incluye un listado parcial de la salida del programa. 11.3 11.3.1 Cena de los Fil´sofos o Cena de los fil´sofos en MPI o Cena de los fil´sofos en MPI. o • Se pretende realizar una implementaci´n del problema de la cena de los fil´sofos en MPI utilizando o o el siguiente esquema: • Tenemos 5 procesos fil´sofos y 5 procesos tenedor (10 procesos en total). Supondremos que los procs. o fil´sofos se identifican con n´mero pares y los tenedores con n´meros impares. El fil´sofo i (i = 0, ..., 4) o u u o ser´ el proc. 2i y el tenedor i ser´ el 2i + 1. a a Cena de los fil´sofos. Programa principal o creado October 4, 2013- p´gina 218 / 222 a
  • 219. SCD (13-14). Pr´ctica 3. Implementaci´n de algoritmos distribuidos con MPI.. a o § #include "mpi.h" #include <iostream> #include <time.h> #include <stdlib.h> ... void Filosofo(int id, int nprocesos); // Codigo proc. Filosofo void Tenedor (int id, int nprocesos); // Codigo proc. Tenedor int main(int argc,char** argv ){ int rank,size; srand(time(0)); MPI_Init( &argc, &argv ); MPI_Comm_rank( MPI_COMM_WORLD, &rank ); MPI_Comm_size( MPI_COMM_WORLD, &size ); if( size!=10){ if (rank == 0) cout<<"El numero de procesos debe ser 10"<<endl<<flush; MPI_Finalize( ); return 0; } if ((rank%2) == 0) Filosofo(rank,size); // Los pares son Filosofos else Tenedor(rank,size); // Los impares son Tenedores MPI_Finalize(); return 0; } ¦ ¤ ¥ Procesos fil´sofos o • En principio, cada fil´sofo realiza repetidamente la siguiente secuencia de acciones: o ◾ Pensar (sleep aleatorio). ◾ Tomar los tenedores (primero el tenedor izquierdo y despu´s el derecho). e ◾ Comer (sleep aleatorio). ◾ Soltar tenedores (en el mismo orden). • Las acciones pensar y comer pueden implementarse mediante un mensaje por pantalla seguido de un retardo durante un tiempo aleatorio. Las acciones de tomar tenedores y soltar tenedores pueden implementarse enviando mensajes de petici´n y de liberaci´n a los procesos tenedor situados a ambos o o lados de cada fil´sofo. o Plantilla de la Funci´n Filosofo o § void Filosofo(int id, int nprocesos){ int izq=(id+1)%nprocesos;int der=(id-1+nprocesos)%nprocesos; while(1){ //Solicita tenedor izquierdo cout<<"Filosofo "<<id<< " solicita tenedor izq ..."<<izq <<endl<<flush; // ... //Solicita tenedor derecho creado October 4, 2013- p´gina 219 / 222 a ¤
  • 220. SCD (13-14). Pr´ctica 3. Implementaci´n de algoritmos distribuidos con MPI.. a o cout<<"Filosofo "<<id<< " coge tenedor der ..."<<der <<endl<<flush; // ... cout<<"Filosofo "<<id<< " COMIENDO"<<endl<<flush; sleep((rand() % 3)+1); //comiendo //suelta el tenedor izquierdo cout<<"Filosofo "<<id<< " suelta tenedor izq ..."<<izq <<endl<<flush; // ... //suelta el tenedor derecho cout<<"Filosofo "<<id<< " suelta tenedor der ..."<<der <<endl<<flush; // ... cout<<"Filosofo "<<id<< " PENSANDO"<<endl<<flush; sleep((rand()%3)+1 );//pensando } } ¦ ¥ Procesos tenedor • Un tenedor solamente podr´ ser asignado a uno de los dos fil´sofos que realicen la petici´n. Hasta a o o que el tenedor no sea liberado no podr´ ser asignado de nuevo. Cada proceso tenedor tendr´ que a a ejecutar repetidamente la siguiente secuencia de acciones: ◾ Esperar mensajes de petici´n de tenedor y recibir uno. o ◾ Esperar mensaje de liberaci´n. o § void Tenedor(int id, int nprocesos){ int buf; MPI_Status status; int Filo; while(1){ // Espera un peticion desde cualquier filosofo vecino ... // ... // Recibe la peticion del filosofo ... // ... cout<<"Ten. "<<id<<" recibe petic. de "<<Filo<<endl<<flush; // Espera a que el filosofo suelte el tenedor... // ... cout<<"Ten. "<<id<<" recibe liberac. de "<<Filo<<endl<<flush; } } ¦ Ejercicio propuesto • Implementar una soluci´n distribuida al problema de los fil´sofos de acuerdo con el esquema descrito o o en las plantillas. Usar la operaci´n s´ o ıncrona de env´ MPI Ssend para realizar las peticiones y ıo liberaciones de tenedores. • El esquema propuesto (cada fil´sofo coge primero el tenedor de su izquierda y despu´s el de la derecha) o e puede conducir a interbloqueo. Identificar la secuencia de peticiones de fil´sofos que conduce a ino terbloqueo en el programa y realizar peque˜as modificaciones en el programa (y en el comportamiento n de las entidades que participan) que eliminan la posibilidad de interbloqueo (sin a˜adir nuevos pron cesos). creado October 4, 2013- p´gina 220 / 222 a ¤ ¥
  • 221. SCD (13-14). Pr´ctica 3. Implementaci´n de algoritmos distribuidos con MPI.. a o Documentaci´n para el portafolios o Los alumnos redactar´n un documento donde se responda de forma razonada a cada uno de los siguientes a puntos: 1. Describe los aspectos m´s destacados de tu soluci´n al problema de los fil´sofos, la situaci´n que a o o o conduce al interbloqueo y tu soluci´n al problema del interbloqueo. o 2. Incluye el c´digo fuente completo de la soluci´n adoptada para evitar la posibilidad de interbloqueo. o o 3. Incluye un listado parcial de la salida de este programa. 11.3.2 Cena de los fil´sofos con camarero en MPI o Cena de los fil´sofos con camarero o • Una forma de evitar la posibilidad de interbloqueo consiste en impedir que todos los fil´sofos intenten o ejecutar la acci´n de “tomar tenedor al mismo tiempo. Para ello podemos usar un proceso camarero o central que permita sentarse a la mesa como m´ximo a 4 fil´sofos. Podemos suponer que tenemos 11 a o procesos y que el camarero es el proc. 10. Proceso fil´sofo con Camarero central o • Ahora, cada fil´sofo ejecutar´ repetidamente la siguiente secuencia de acciones: o a ◾ ◾ ◾ ◾ ◾ ◾ Pensar Sentarse Tomar tenedores Comer Soltar tenedores Levantarse • Cada fil´sofo pedir´ permiso para sentarse o levantarse enviando un mensaje al camarero, el cual o a llevar´ una cuenta del n´mero de fil´sofos que hay sentados a la mesa en cada momento. a u o creado October 4, 2013- p´gina 221 / 222 a
  • 222. SCD (13-14). Pr´ctica 3. Implementaci´n de algoritmos distribuidos con MPI.. a o Ejercicio propuesto • Implementar una soluci´n distribuida al problema de los fil´sofos con camarero central que se ha o o descrito, usando MPI. • Documentaci´n para el portafolios o Los alumnos redactar´n un documento donde se responda de forma razonada a cada uno de los sigua ientes puntos: 1. Describe tu soluci´n al problema de los fil´sofos con camarero central. o o 2. Incluye el c´digo fuente completo de la soluci´n adoptada. o o 3. Incluye un listado parcial de la salida del programa. creado October 4, 2013- p´gina 222 / 222 a