TEMA 2 - Escuela de Ingenierías Industriales

Anuncio
Programación de aplicaciones en T.R.
TEMA 2
Lenguajes para aplicaciones en tiempo real
Programación a pequeña escala
Programación a gran escala
Programación concurrente
Sistemas operativos
Programación de
aplicaciones en tiempo real
1
2
Proyecto.
Conjunto de tareas y actividades, limitadas en el
tiempo, encaminadas a alcanzar un objetivo bien
definido, en un plazo determinado y con unos recursos
dados (humanos, materiales, presupuestarios, etc.).
Etapas en la gestión de proyectos:
Lenguajes para
aplicaciones
en tiempo real
Iniciación del proyecto: objetivos y plazo de ejecución.
Calificación del proyecto: evaluación global
Estimación de cargas y coste
Estimación de riesgos
Aceptación o rechazo de emprender el proyecto
Desarrollo del proyecto: realización y control del desarrollo
Planificación y descomposición en etapas y tareas
Lanzamiento del proyecto: ejecución y desarrollo
Seguimiento y control del proyecto.
Cierre de etapas
3
4
Cierre del proyecto.
Proyectos informáticos.
La aplicación de los métodos de ingeniería a los
proyectos informáticos ha dado lugar a un conjunto de
técnicas conocidas como Ingeniería del Software:
Aplicación práctica del conocimiento científico al
diseño y construcción de programas, y la
documentación necesaria para el desarrollo,
operación y mantenimiento de los mismos.
Etapas en la gestión de proyectos informáticos:
ANÁLISIS
EL CICLO DE VIDA
CODIFICACIÓN
MODELOS DE CICLO DE VIDA:
Definición: especificaciones y requisitos.
Diseño: preliminar, detallado y técnico.
Desarrollo: codificaciones y pruebas.
Integración: implantación, operación y mantenimiento.
CASCADA
PROTOTIPOS
VERSIONES SUCESIVAS
5
TRANSFORMACIONES
EN ESPIRAL
6
1
SISTEMA
REQUISITOS
DEFINICIÓN
SOFTWARE
DISEÑO PRELIMINAR
DISEÑO DE GESTIÓN
ESPECIFICACIÓN
ANALISIS
DISEÑO DETALLADO
DISEÑO DE DATOS
DISEÑO
DISEÑO
PROGRAMAS
DISEÑO ARQUITECTÓNICO
DISEÑO TÉCNICO
DISEÑO DE PROCEDIMIENTOS
CODIFICACION
DESARROLLO
DISEÑO DE INTERFACES
PRUEBAS
INTEGRACIÓN
IMPLANTACIÓN
OPERACIÓN
7
8
Lenguajes para aplicaciones T.R.
La elección de un lenguaje tiene
implicaciones en la seguridad, fiabilidad y
coste del sistema final.
Coste o esfuerzo
Coste total
del sw
Coste de las
interfaces
Coste por módulo
Región de
coste mínimo
nº de módulos
Requisitos de un buen lenguaje para desarrollo
de aplicaciones en tiempo real
Características que ayudan a la construcción de
software seguro y fiable.
Técnicas de programación modular.
Facilidades para soportar concurrencia.
9
Lenguajes para aplicaciones T.R.
10
Lenguajes para aplicaciones T.R.
Los sistemas de tiempo real frecuentemente son
sistemas grandes y complejos, lo cual implica que su
desarrollo y mantenimiento sea costoso. Además, estos
sistemas tienen que responder a eventos externos
garantizando un mínimo de tiempo de respuesta,
utilizando un amplio rango de dispositivos de interfaz,
incluyendo dispositivos que no son estándar. En muchas
aplicaciones, la eficiencia en la utilización del hardware
del computador es vital para conseguir la velocidad de
operación necesaria.
Para conseguir una utilización más eficiente de la CPU y
acceso a los dispositivos de interfaz e interrupciones, los
primeros sistemas de tiempo real fueron programados
utilizando lenguajes a nivel de ensamblador. Estos aún
se sigue utilizando, sobre todo para sistemas pequeños
con requisitos de velocidad de cálculo altos.
11
12
Pero la programación en ensamblador no es nada
atractiva, de forma que la insatisfacción con los lenguajes
ensambladores supuso el desarrollo de lenguajes de
alto nivel. De esta forma, se desarrollaron lenguajes
como FORTRAN, RTL, PASCAL, MODULA o C. Pero la
limitación de todos ellos es que, esencialmente, estaban
diseñados para producir programas secuenciales.
2
Lenguajes para aplicaciones T.R.
Lenguajes para aplicaciones T.R.
Existen especificaciones relativas a los STR que deben
ser cumplidas por estos lenguajes.
Técnicas para que la aplicación sea separada en
módulos.
Facilidades relacionadas con el soporte de la
concurrencia.
El ciclo de vida en el desarrollo de una aplicación tiene
las siguientes etapas:
Análisis.
Diseño e implantación.
Hay que detectar los errores en las primeras etapas de
desarrollo. Participan muchas personas en su desarrollo
por lo que resulta interesante la separación de la
aplicación en módulos que serán desarrollados por
equipos, teniendo en cuenta su relación e interacción con
otros módulos.
En los STR vamos a tener varias tareas y tenemos que
que representar la concurrencia de estas tareas. Para
ello necesitamos soporte para la construcción de
módulos, para la construcción y manejo de tareas,
interrupciones, gestión de excepciones,…
Mantenimiento.
13
Lenguajes. Elementos básicos
14
Lenguajes. Soporte de concurrencia
Variables y constantes.
Tipos de datos.
Estructuras de control.
Reglas de ámbito y visibilidad.
Métodos de modularidad y compilación.
Gestión de excepciones.
Construcción de módulos
Creación y gestión de tareas
Gestión de interrupciones y dispositivos
Comunicación entre tareas
Exclusión mútua.
Gestión de excepciones.
15
Lenguajes. Características deseables
16
Seguridad
La seguridad de un lenguaje se mide en términos de la
efectividad en la detección automática de errores. Hay
una serie de características del lenguaje que ayudan a
detectar los errores :
Seguridad
Legibilidad
Flexibilidad
Simplicidad
Portabilidad
Eficiencia
soporte
de
modularidad
independiente)
(compilación
y
verificación
declaración forzada de variables
un rango de tipos de datos adecuado, incluyendo tipos subrango
tipado de variables
sintaxis no ambigua.
17
Los errores pueden ser lógicos o de sintaxis. Los
segundos pueden ser detectados por el compilador.
18
3
Seguridad
Legibilidad
No es posible probar exhaustivamente el software, por lo
que la seguridad intrínseca del lenguaje es básica para
el desarrollo de programas fiables.
Desarrollo cruzado: el desarrollo (edición, compilación y
depuración) se realiza en un computador diferente al de
ejecución
Económicamente es importante detectar errores en la
etapa de compilación en vez de en tiempo de ejecución.
Es la medida de la facilidad con que se puede
entender la operación de un programa sin
comentarios adicionales y sin tener que recurrir a
documentación
externa,
como
diagramas
o
descripciones en el lenguaje natural.
La idea es que los programas se van a escribir una vez
pero se van a leer muchas veces para que se puedan
adaptar a las necesidades.
Las comprobaciones realizadas en tiempo de
compilación no generan sobrecargas en tiempo de
ejecución. (El programa se va a ejecutar muchas más
veces de lo que se ha compilado).
19
Legibilidad
20
Legibilidad
Las ventajas que se obtienen haciendo programas
fácilmente entendibles son:
Reducción de los costes de documentación. Mucha de la
documentación está dada por el propio código. Se ha de tener
en cuenta que, además, las personas que van a realizar el
mantenimiento de la aplicación no suelen ser los mismos que la
desarrollaron.
Una detección de errores más fácil.
Un mantenimiento más fácil.
Para conseguir un programa entendible es necesario la
colaboración del programador, ya que es posible
escribir programas ilegibles en cualquier lenguaje.
El problema de la legibilidad es que cada programador
tiene su forma de escribir programas. Por lo tanto se
necesita que el lenguaje sea muy estricto y que exista
una planificación que ponga énfasis en la estructura y en
la elección de los nombre de variables.
Otro inconveniente de la legibilidad es que el código
fuente se hace grande, y cuesta más tiempo escribirlo,
pero es un pequeño coste que hay que pagar por la
seguridad y el mantenimiento del software.
21
Flexibilidad
Un
lenguaje
debe
proporcionar
todas
las
características necesarias para expresar todas las
operaciones que se requieran sin tener que utilizar
complicadas construcciones o recurrir a código
ensamblador. La flexibilidad es una medida de esta
capacidad.
Para sistemas de tiempo real es particularmente
importante ya que es normal tener que controlar
dispositivos de entrada/salida no estándar.
La flexibilidad y la seguridad suelen entrar en conflicto.
En los lenguajes modernos este compromiso se
consigue proporcionando alta flexibilidad y, por medio
del concepto de módulo o paquete, se proporciona un
medio por el cual las operaciones a bajo nivel (es decir,
la no seguras) se pueden ocultar en un número limitado23
de secciones autocontenidas del programa.
22
Simplicidad
Al igual que en otras áreas, lo simple es preferido a lo
complejo. La simplicidad contribuye a la seguridad.
Cuanto más simple es un lenguaje, más fácil es
entender cada una de las instrucciones del programa,
menor es el coste de aprendizaje y más difícil es
cometer errores, por lo que se incrementa la seguridad.
Además reduce el coste y los errores de programación,
así como el tamaño del compilador, el cual proporciona
un código objeto más eficiente.
La simplicidad no tiene que llevar a inconsistencias que
reduzcan la seguridad. Un buen lenguaje no debe
imponer restricciones arbitrarias en la utilización de
ninguna de sus características
24
4
Portabilidad
Portabilidad
La portabilidad es difícil de conseguir en la práctica,
aunque es deseable como un medio de acelerar el
desarrollo de aplicaciones, reduciendo el coste y
aumentando la seguridad. Consiste en que una
aplicación se pueda trasladar de una máquina a otra sin
o con mínimos cambios. No solamente ha de ser
portable en código fuente sino que hay que tener en
cuenta las características de hardware de la máquina.
En forma de código fuente es posible transferir un
programa de un computador a otro, compilando y
ejecutándolo en el computador al cual ha sido
transferido. Pero aún así hay problemas, por ejemplo,
la longitud de palabra de la dos máquinas pueden ser
diferentes y pueden dar problemas con el rango y la
precisión con la que son representados los números.
Otro problema es el direccionamiento de información
(convenios little endian y big endian).
25
Portabilidad
26
Eficiencia
En los sistemas de tiempo real la portabilidad es aún
más difícil de conseguir, ya que con frecuencia hay que
utilizar características específicas del hardware del
computador y del sistema operativo.
En los STR, generalmente las aplicaciones no son
portables. Una solución utilizada en la práctica es
aceptar que un sistema de tiempo real no es
directamente portable y restringir las partes no portables
a unos módulos. Las aplicaciones se desarrollan
pensando que se van a ejecutar en una máquina virtual
y se desarrollan las partes de aplicación dependientes
del hardware en forma de módulos dependientes del
hardware, que se añaden enlazándolos a la aplicación.
Define las prestaciones de un STR. En sistemas de
tiempo real, que deben garantizar un cierto
funcionamiento junto con unas restricciones temporales,
la eficiencia es importante. En los primeros
computadores para sistemas de control, el mayor
énfasis se hizo en la eficiencia del código, tanto en
términos de tamaño del código objeto, como en la
velocidad de operación. Pero al bajar el costo del
hardware y aumentar la velocidad de cálculo, los
criterios de eficiencia han cambiado.
27
Eficiencia
28
Herramientas de desarrollo
En muchas aplicaciones de tiempo real el concepto de
lenguaje
eficiente
ha
cambiado
para
incluir
consideraciones de la seguridad y coste de escritura y
mantenimiento del programa, quedando como de
segunda importancia en muchas aplicaciones la
velocidad y compactación del código. Aunque hay aún
áreas de aplicaciones donde sigue siendo primordial
la velocidad y compactación, por ejemplo en el control
de sistemas electromecánicos, control aeronáutico y en
general en el campo de procesamiento de señales, en
las que todavía es importante el desarrollo en
ensamblador de ciertas partes muy relacionadas con el
hardware.
29
Ensamblador
Lenguajes de alto nivel
Montador
Cargador
Puesta a punto
30
5
ENSAMBLADOR
ENSAMBLADOR
Es un programa que acepta código fuente y
produce código máquina.
Ensambladores absolutos
El fichero fuente con directiva de localización
Produce código ejecutable que se puede cargar en el
procesador de destino
Pb: fichero fuente con todo el código o bien cálculo de
ocupaciones y direcciones
Relación 1:1 Instrucción fuente - instrucción micro
Campos en el código fuente ensamblador
Etiqueta: Referencia simbólica de una posición en
memoria
Código de operación
Ensambladores relocalizables
Ficheros fuente sin directivas de localización
La salida no es código ejecutable → fichero objeto
Necesidad de un montador de enlaces
Mnemónico de una instrucción
Directiva del ensamblador (p.e. ORG)
Operandos
Nombre de registros
Constantes numérica o simbólicas
Etiquetas
Expresiones agebraicas
31
32
Comentarios
LENGUAJES DE ALTO NIVEL
LENGUAJES DE ALTO NIVEL
Lenguajes de alto nivel
Requisitos de un lenguaje para la programación
de μC
Desarrollo más rápido (↑ abstracción)
Codificación más rápida y segura
Puesta a punto de la lógica del programa más sencilla
=> disminución de costes
Acceso directo a memoria y hardware para lectura y
escritura
Programación de periféricos
↓ eficiencia
↑ ocupación en memoria
Reescritura de algunas partes críticas en
ensamblador
Posibilidad de llamar a rutinas en ensamblador o
insertar código máquina
Conexión directa con interrupciones
La mayoría de la aplicaciones basarán gran parte de su
funcionamiento en interrupciones
Prestaciones, carácter asíncrono de los eventos
Disminución de la ocupación de memoria
Aumento de las prestaciones
Generación de código eficiente en ocupación de
memoria y velocidad de ejecución
33
LENGUAJES DE ALTO NIVEL
Ada95
Incluye concurrencia, tiempo
real, acceso a recursos de
bajo nivel y un potente
tratamiento de las
excepciones
Transportabilidad,
Legibilidad, Eficiencia,
Seguridad (chequeos del
compilador)
Genera código
excesivamente extenso
En el futuro se dispondrá de
compiladores que
contemplen un perfil mínimo
del lenguaje
Se dispone de poca memoria
34
LENGUAJES DE ALTO NIVEL, EL C
C
ANSI C -> estándar
Alto nivel que retiene el
contacto con el hardware ( ↓
abstracción, facilidad
programación periféricos)
Generación de código muy
optimizable
Extensiones para cumplir
todos los requisitos
Concurrencia => kernel
Sistema empotrado ≠ computador con SO + E/S
estándar
No funciones de E/S
No printf
No ficheros
...
Código y datos en posiciones concretas de memoria
ROM, RAM, EEPROM,...
No código ejecutable relocalizable (<= no SO)
Directivas de posicionamiento + Linker
Actualmente la industria emplea
mayoritariamente el C
para el desarrollo de sistemas
empotrados
Programación de periféricos
Acceso a registros físicos
Servicio de interrupciones
35
36
6
LENGUAJES DE ALTO NIVEL, EL C
EL MONTADOR
Acceso al bajo nivel
Sólo necesario cuando el
compilador genera código
relocalizable
Funciones
Enlace con ensamblador
P.e. CLI
Manejo de bits
Fuente
Ensamblador
Fuente C
Compilador
Cruzado
Ensamblador
Cruzado
Ejecución sobre máquina desnuda
Establecer las referencia
cruzadas entre módulos
Enlazar con librerías
Asignar valor absoluto a
símbolos, etiquetas
Establecer las direcciones
de carga
Valor inicial del puntero de
pila
Se viste la máquina mediante ficheros de cabecera
Funciones específicas de acceso al hardware
Directivas
Expansión en línea (inline)
Intercalado de instrucciones en ensamblador
Rutinas de servicio de interrupción
Posicionamiento absoluto
Objeto
Relocalizable
Librerías
Objeto
Relocalizable
Fichero
Configuración
Montador de
Enlaces
Ejecutable
No Relocalizable
Cargador
Máscara
Microcontrolador
37
EL CARGADOR
38
PUESTA A PUNTO
Carga del programa ejecutable en la memoria
del microcontrolador
Debuggers
Dos posibles niveles
Código fuente
Código máquina
Sistema operativo
Carga por línea serie, ethernet, ...
Paso a paso
Posibilidades
Visualizado de los efectos de la ejecución
Monitor
Hardware
Breakpoints
Memoria RAM
Memoria EPROM/EEPROM
Detención de la ejecución del programa -> control al
debugger
La instrucción donde debe detenerse el programa es
cambiada por un interrupción software
Existen micros que se autograban
Grabador de la memoria PROM
Máscara
Visualizado y alteración de registros y memoria
Un fichero de listado es imprescindible
39
Código fuente + ensamblador generado + Tabla de
40
PUESTA A PUNTO
Posibilidades clasificadas por potencia:
Simuladores
La memoria y registros pueden ser observados y alterados
No interrupciones, ni hardware adicional. No tiempo real
Programación a
pequeña escala
Debuggers residentes
Programa de aplicación y monitor conviven en el μC
No ejecución simultánea
Visualización y actualización de memoria, breakpoints, …
Emuladores
Hardware que “emula” al μC y además permite obtener
información y actuar sobre la aplicación sin gastar recursos
del μC ni alterar la evolución temporal
Analizadores lógicos
41
42
7
Programación a pequeña escala
Entre las características de los lenguajes de alto
nivel podemos distinguir aquellas que ayudan al
proceso de descomposición y aquellas que facilitan
la programación de componentes bien definidos.
Estas dos conjuntos se describen como:
Cuestiones a tener en cuenta cuando se escriben
programas:
Recuerda que tu código puede ser analizado por
otras personas (al menos un 40% de las líneas de un
programa deben ser comentarios)
•Soporte para la programación a gran escala.
Usa nombres de variables con significado.
•Soporte para la programación a pequeña
escala.
Los comentarios incrementan la comprensión de un
programa.
43
Puntos básicos
44
Sintaxis y legibilidad
BEGIN
NST = TICKS ( ) + ST;
T = TICKS ( ) + ST;
LOOP
WHILE TICKS ( ) < NST DO (*NADA*) END;
T := TICKS ( );
CC;
NST : = T + ST;
IF KEYPRESSED ( ) THEN EXIT;
END;
END;
END;
Sintaxis y legibilidad
Declaración e inicialiación de variables y
constantes
Modularidad y variables
Compilación y programas modulares
Tipos de datos
Estructuras de control del flujo de ejecución
45
Sintaxis y legibilidad
BEGIN
NextSampleTime = TICKS ( ) + SampleTime;
Time = TICKS ( ) + SampleTime;
LOOP
WHILE TICKS ( ) < NextSampleTime DO
(*NADA*)
END;
Time := TICKS ( );
ControlCalculations;
NextSampleTime : = Time + SampleTime;
IF KEYPRESSED ( ) THEN
EXIT;
END;
END;
END;
46
Declaración e inicialización
Declaración de entidades:
Necesidades de almacenamiento
Nombres explícitos
100 ERROR=0
.....
200 IF X=Y THEN GOTO 300
250 EROR = 1
300 ...
...
400 IF ERROR=0 GOTO 1000
...
47
48
8
Ejemplo de Fortran (mala convención léxica)
DO 20 I = 1, 100
Declaración e inicialización
Inicialización de entidades:
Bucle iterando I desde 1 hasta 100
Dar un valor inicial cuando es declarada
No deja al compilador tomar la decisión.
En la sonda Viking Venus, un programador escríbió
DO 20 I = 1. 100
El compilador interpretó esto como una sentencia de asignación pues,
ignorando los espacios, se tiene:
Constantes
DO20I = 1.100
En Fortran, las variables no necesitan declararse, y aquellas que empiezan por
D se asumen como de tipo realy y 1.100 es, literalmente, un número real.
Valores de entidades físicas o matemáticas deben
permanecer fijos en la ejecución del programa.
Inicializar una variable no es seguro. Puede
modificarse sin querer en otro punto del probrama.
const en C
49
Ambito y visibilidad
50
Asignación dinámica de memoria
El ámbito de una variable se define como la
región de un programa en la que la variable es
potenciable accesible o modificable.
La región donde es realmente accesible o
modificable define la visibilidad.
Problemas:
las variables declaradas en un procedimiento no
pueden usarse para mantener valores en la
siguiente entrada al procedimiento”.
En C existen las variables static.
Si un procedimiento se llama recursivamente es
posible que el programa pueda fallar debido a
que no haya memoria disponible.
Crecimiento incontrolado de la pila
malloc() y free()
51
Variables globales y locales
52
Tipos de datos
Existen argumentos a favor y en contra de ambas.
Variables locales: es una buena práctica declarar
entidades cerca de donde van a ser usadas, y se
limita el ámbito y la visibilidad de la entidad.
Variables globales: es la única forma de garantizar
la consistencia y el control del nombre de
entidades en sistemas grandes que son
desarrollados por equipos de programadores.
Compromiso: declarar como globales a las
entidades que están directamente relacionadas
con el mundo exterior, y locales al resto.
53
La asignación de un tipo a una entidad define:
El conjunto de valores que puede tomar la entidad.
El conjunto de operaciones que se puede realizar
con la entidad.
La riqueza de tipos y la rigurosidad con que se
impone la compatibilidad de tipos en un lenguaje
tienen una gran influencia en la seguridad.
Fuertemente tipados: imponen rigurosamente la
compatibilidad de tipos.
Débilmente tipados: no imponen compatibilidad
54
de tipos.
9
Tipificación de Datos
Conversión de Tipos en el Lenguaje C
Conversión Automática de Tipos: Cuando un operador
tiene operandos de tipos diferentes, éstos se convierten
a un tipo común “razonable”:
Un lenguaje con tipificación de datos requiere que cada
variable y/o constante sea de un tipo específico (entero,
real, carácter, etc.) declarado antes de usar la variable.
char
Diferentes niveles de comprobación de tipos:
Sin tipos (Ej: BASIC)
Conversión automática de tipos (Ej: C)
Comprobación de tipos fuerte (Ej: ADA)
int
float
double
long double
short
Dentro de los lenguajes con tipificación de datos, puede
realizarse:
comprobación estática de tipos (en tiempo de compilación)
comprobación dinámica de tipos (en tiempo de ejecución)
Las reglas se complican al considerar enteros y chars
con y sin signo (resultado depende muchas veces de la
máquina).
55
Conversión de Tipos en el Lenguaje C
56
El lenguaje C
Es secuencial
La principal unidad de estructuración son las
funciones (aunque los ficheros pueden usarse para
ayudar a la compilación separada)
Estructurado en bloques (llamados declaraciones
compuestas)
Ejemplos de conversión automática:
Operaciones
int i,j; double k;
i = j + k;
k = i + j;
Llamada a funciones
función definida como: double sqrt(double)
invocación: k = sqrt(i);
{
< parte declarativa >
Casting: Conversión Explícita de Tipos (es bueno
explicitarla siempre!)
< secuencia de sentencias >
}
57
Ejemplo en C
La parte declarativa no puede contener funciones
La secuencia de sentencias puede contener
58
declaraciones compuestas
Tipos Discretos
int mayor(vector X, int len)
Ada
Java
C
{
int max = 0;
int i;
Asignación es =
Integer
Igualdad es = =
for (i = 0; i < len; i++) {
int
int
short
short
long
long
if(X[i] > max) max = X[i];
byte
}
Boolean
return max;
}
boolean
Character
59
char
Wide_Character
char
wchar_t
Enumeration types
None
typedef enum
60
10
Tipos Discretos
Tipos Discretos
• Ada y Java son fuertemente tipados, y soportan la
conversión explícita de tipos; sin embargo, C no es tán seguro
en cuanto a tipos, por ejemplo:
int a; float b;
a = b;
/* en C */
Typedef int newint;
Typedef enum {xplane, yplane, xzplane} dimension
/* en Ada */
Type Dimension is (Xplane, Yplane);
Type map is (Xplane, Yplane)
Line, Force : Dimension,
Grid : Map;
•C y Ada permiten duplicación de tipos o la definición de
nuevos tipos basada en tipos básicos.
61
Tipos de datos estructurados
62
Estructuras de Control
Estructuras secuenciales
Java soporta arrays,
En Java, C, y Ada una secuencia se indica con {}
En Ada es necesario establecer explícitamente una
secuencia vacía:
begin –Ada
null;
end;
Esto no es necesario en C y Java
Ada y C soportan arrays y registros (estructuras)
--Ada
Max: Const Integer:=10;
Type Reading_T is array(0..Max-1) of Float;
Size: Const Integer:=Max-1;
Type Switches_T is array(0..Size, 0..Size) of Boolean;
Reading: Reading_T;
Switches: Switches_T;
63
Estructuras de Control
Estructuras de Control
Estructuras de decisión :
If, if then else
Bucles
Iteración
Recursión
For
--Ada
for I in 0..9 loop
A(I):=I,
end loop;
64
while
--Ada
/* C and Java*/
while<expresión booleana >loop
<sentencias>
end loop;
while (expresion){
<sentencias>
}
/* C y Java*/
for (i=0;i<=9;i++){
A[i] = i;
}
65
66
11
Programar
Programación estructurada
TRANSFORMAR EL DISEÑ
DISEÑO EN UN PROGRAMA
EJECUTABLE EN UNA PLATAFORMA ESPECÍ
ESPECÍFICA
Características de una buena programación:
la estructura arquitectónica definida durante el diseño es fácilmente
reconocible en el código
los niveles de abstracción del diseño se conservan
las interfaces entre partes del programa son descritas
explícitamente
la consistencia de objetos y operaciones puede ser probada por el
propio compilador
Alcanzar estas características depende de:
la programación estructurada
la elección del lenguaje de programación
la elección del entorno de programación
el estilo de programación
Dijkstra: “GOTO statement considered harmful”
Calidad de un programa es inversamente
proporcional al número de sentencias GOTO
utilizadas.
Programa Estructurado
programa = secuencia de construcciones lógicas
construcciones lógicas = secuencia, condición,
repetición
cada construcción tiene 1 entrada y 1 salida
67
Programación estructurada
68
Reglas para estructurar un diagrama de flujo
1) Mover el punto de destino del salto (donde se
reunifica el flujo) y duplicar las acciones que
quedan en medio.
Características del código resultante
número mínimo de GOTO’s
utiliza bloques para estructurar
minimiza el número de variables no locales
BEGIN
BEGIN
A1
A1
Técnicas para eliminar los GOTO’s
duplicación de código
introducción de procedimientos
utilización de variables auxiliares
utilización de banderas
69
Reglas para estructurar un diagrama de flujo
2) Mover el punto de destino del salto más allá
de los chequeos de condiciones añadiendo
instrucciones adicionales que hagan
innecesario el chequeo de condiciones.
BEGIN
BEGIN
A1
A1
A3
A3
B1
F
B1
T
F
A2
A2
A2
B1
B1
A3
A3
B2
B2
A4
A4
END
END
A1
70
Alternativa a los diagramas de flujo
Diagramas de Flujo
fomentan uso de “GOTO”
impiden expresar estructuras de control de alto nivel
Diagrama de Nassi-Schneiderman o de cajas
impiden el uso de “GOTO”
se determina fácilmente el ámbito de datos locales o
globales
recursividad se representa fácilmente
T
A2
B2:= TRU
B2
F
T
B2
F
T
END
END
71
72
12
Alternativa a los diagramas de flujo
SECUENCIA
Alternativa a los diagramas de flujo
IF-THEN-ELSE:
acción 1
SELECCIÓN (“switch-case”)
cond.
F
T
parte
parte
else
then
acción 2
...
caso de condición
acción n
cond. de bucle
parte
do-while
valor
valor
...
parte
case
parte
case
...
REPETICIÓN
Principales desventajas
parte
repeatuntil
difíciles de modificar”
“Fundamentalista”: no permiten expresar
ningún GOTO
cond. de bucle
73
74
Inconvenientes
Alternativa a los diagramas de flujo
el código resultante
puede ser más largo
el código resultante
puede ser menos
eficiente
algún “gurú” se
puede reir de
nuestros programas
/*Ejemplo: itoa: convierte n a caracteres en texto */
void itoa(int n, char texto[])
{
int i, signo;
if ((signo = n) < o)
/*guardo el signo */
n = -n;
/*hago n positivo */
i = 0;
do {
/* genero dígitos en orden inverso */
texto[i++] = n % 10 + ‘0’;
} while (( n /=10 ) >0);
if ( signo <0)
/*agrego signo de menos? */
texto[i++] = ‘-’;
texto[i] = ‘\0’;
invertir(texto);
}
75
GOTOs útiles
y
ventajas
más entendible; más
fácil de leer
mayor confiabilidad
más fácil de modificar
mayor localidad
más fácil de chequear
quien ríe último, ríe
mejor!
ES MUCHO MÁ
MÁS FÁ
FÁCIL OPTIMIZAR
UN PROGRAMA CORRECTO
QUE
CORREGIR UN PROGRAMA OPTIMIZADO
QUE CONTIENE ERRORES
76
GOTOs útiles
Para realizar estructuras de control no disponibles (por
ejemplo en ensamblador)
Para interrumpir iteraciones
“break” y “continue” en el lenguaje C:
Para salir rápidamente de dentro de varios niveles de
iteración
buscar un elemento en una matriz y abandonar la búsqueda
inmediatamente después de encontrado
/*trim: elimina blancos, tabuladores y NL al final*/
int trim(char texto[])
{
int n;
for (n = strlen(texto)-1; n >=0; n --)
if (texto[n] !=‘ ‘ && texto[n] !=‘\t’ && texto[n] !=‘\n’)
break;
texto[n+1] = ‘\0’;
return n;
}
Para optimizar programas estructurados
77
78
13
Estilo de programación
Estilo de programación
Estructura
Los programas se escriben una sola vez, pero
se leen (y modifican) muchas veces...
⇒ Vale la pena escribirlos de modo que sean
entendibles!
elegir instrucciones adecuadas
Ejemplo: Tres instrucciones equivalentes en “C”:
n = n * 8;
n *= 010; /* constante en octal */
n <<=3;
Elementos de un buen estilo:
Estructura
Elocuencia
Forma externa
Uso de comentarios
en lo posible proceder de acuerdo a los criterios de la
prog. estructurada (... pero sin fundamentalismos!)
79
Estilo de programación
80
Estilo de programación
Elocuencia:
Elocuencia (cont.)
Elección de nombres apropiados para objetos y operaciones
Ser elocuente y consecuente, aún cuando los nombres
sean largos
Utilizar abreviaturas usuales
Ejemplo: CBCPJP = Controlador de la Bomba de Calor,
Programador: Juan Pérez
No mezclar distintos idiomas
Utilizar
palabras principales para valores (ancho, tecla,....)
expr. con verbos para actividades (calc_ancho, lee_tecla...)
expr. con adjetivos para condiciones (valido, muy_alto,...)
Utilizar convenciones
Ejemplo:
Tipos definidos por el usuario: comenzar con “T_”, TODO
MAYÚSCULA: T_PERSONA
Constantes: TODO_ MAYÚSCULA
Variables globales: comienzan con “gbl_”: gbl_unEjemplo
Punteros: comenzar con “ptr_”: ptr_unPuntero
Variables locales y funciones: todo minúscula
Nombres compuestos por varias palabras:
separarConMayuscula
81
Estilo de programación
82
Comentarios
Comentarios de prólogo
Encabezado de cada módulo
Formato
Forma externa
separación de declaraciones e instrucciones
declaraciones con una estructura sistemática:
1. Propósito, función del módulo
2. Descripción de la interfaz, incluyendo:
constantes, tipos de datos variables
organización de la descripción de la interfaz (lista de
parámetros) en
ejemplo de una “secuencia de llamada”
descripción de cada uno de los argumentos
lista de todos los módulos subordinados
variables de entrada
variables de salida
variables de entrada/salida
3. Explicaciones pertinentes, como por ejemplo
variables importantes y su uso
modo de funcionamiento (algoritmos)
restricciones y limitaciones
separación de textos de programa y comentarios
utilizar indentación para resaltar estructura del
programa
4. Historia del desarrollo, incluyendo
83
autor, revisor y fecha.
fecha y descripción de las modificaciones
84
14
Comentarios
Desde código fuente en C hasta el ejecutable
Comentarios descriptivos
Deben proporcionar información adicional (si
no, más vale ahorrárselos!)
Deben ser correctos... un comentario no
actualizado puede hacer perder mucho
tiempo!
En general, es mejor comentar bloques que
líneas de código.
Headers
Headersdel
del
Sistema
Sistema
Código Fuente
pre-procesador
Código Fuente
C preprocesado
compilador
Headers
Headersdel
del
Usuario
Usuario
inclusión de archivos
substitución de macros
compilación condicional
una o dos pasadas
Código fuente en
ensamblador
ensamblador
Código objeto
Código objeto
Bibiliotecas
Bibiliotecasdel
del
Sistema
Sistema
Otros
Otrosarchivos
archivosde
de
código
códigoobjeto
objeto
link-loader
EJECUTABLE
85
Dicen los que saben...
Bibiliotecas
Bibiliotecasdel
del
usuario
usuario
86
Dicen los que saben...
Que es bueno evitar “programar astutamente”
Que hay que evitar las variables globales
pueden ser manipuladas desde cualquier lado
una modificación puede tener efectos inesperados
Que es mejor evitar los “efectos colaterales”
Que los programas son en primer lugar un medio
de comunicación con otros programadores
primero correcto, después eficiente
primero pensar, después compilar
antes de compilar, “ejecutar mentalmente” el programa
realizar inspecciones, explicarle a otros
Que es posible escribir programas de buena
calidad usando lenguajes no estructurados
Que es posible escribir programas malos utilizando
lenguajes buenos
Que hay que evitar muchos niveles de if-then-else
máximo 3 niveles
Que los programadores buenos lo son
independientemente del lenguaje de programación
Que los programadores malos lo son
independientemente del lenguaje de programación
87
88
Descomposición y Abstracción
Decomposición — división sistemática de un
sistema complejo en partes cada vez más
pequeñas hasta que los componentes sean
aislados y se puedan entender y manipular por
individuos o pequeños grupos.
TOP DOWN DESIGN
Programación a gran
escala
Abstracción — especificación de la parte
esencial del componente para una posterior
consideración de los detalles del mismo
BOTTOM UP DESIGN
89
90
15
Modulos
Ocultación de Información
Colección de objetos y operaciones lógicamente
relacionados.
Encapsulación — técnica para aislar una
función del sistema dentro de un módulo con
una especificación precisa del interfaz
ocultación de información
compilación separada
tipos de datos abstractos
¿Como deberían descomponerse grandes
sistemas en módulos?
La respuesta está en la Ingeniería del Software!
91
Tipos abstractos de datos
Una estructura modular soporta visibilidad reducida
permitiendo que la información sea ocultada en su
cuerpo.
La especificación y el cuerpo de un módulo puede darse
por separado. Idealmente, la especificación debería ser
compilable sin haber escrito el cuerpo
P. Ej., en Ada hay una especificación de package y un
cuerpo de package; relación formal; errores en tiempo
de compilación.
En C, los módulos no están tan bien formalizados.
Habitualmente, los programadores crean un fichero .h
que contiene el interfaz a un módulo, y un fichero .c para
el cuerpo. No hay relación formal. Los errores se
detectan en tiempo de enlace (link)
92
Tipos abstractos de datos
Ejemplo de especificación de un tipo abstracto de datos:
Existen lenguajes de programación que permiten crear
nuevos tipos de datos, más específicos que los tipos de
datos generales previstos en el lenguaje.
Un tipo abstracto de datos se especifica indicando:
su dominio (es decir, los datos que lo integran)
los servicios disponibles para operar sobre la
estructura de datos
las propiedades de dichos servicios.
TIPO: STACK[X]
FUNCIONES:
empty: STACK[X] -> BOOLEAN
new: -> STACK[X]
push: X x STACK[X] -> STACK[X]
pop: STACK[X] -> STACK[X]
PRECONDICIONES:
pre pop(s: STACK[X]) = not empty(s)
AXIOMAS:
Para todo x:X, s: STACK[X]:
empty(new())
not empty(push(x,s))
pop(push(x,s)) = s
93
Tipos abstractos de datos: Ejemplos (1)
94
Tipos abstractos de datos: Ejemplos (1)
Definición del tipo de datos “COMPLEJO” en ADA:
Definición del tipo de datos “COMPLEJO” en ADA (cont.):
package NUMEROS_COMPLEJOS is
type COMPLEJO is
record
REAL: FLOAT:= 0.0;
IMAG: FLOAT:= 0.0;
end record;
function EQUAL (X,Y: COMPLEJO) return BOOLEAN;
function ¨+¨
(X,Y: COMPLEJO) return COMPLEJO;
function ¨-¨
(X,Y: COMPLEJO) return COMPLEJO;
function ¨*¨
(X,Y: COMPLEJO) return COMPLEJO;
function ¨/¨
(X,Y: COMPLEJO) return COMPLEJO;
end; -- fin de la especificación del tipo
95
package body NUMEROS_COMPLEJOS is
function EQUAL (X,Y: COMPLEJO) return BOOLEAN is
begin
if (X.REAL = Y.REAL) and (X.IMAG = Y.IMAG)
then
return TRUE;
else
return FALSE;
end if;
end EQUAL;
... siguen las demás operaciones....
96
16
Tipos abstractos de datos: Ejemplos (2)
Tipos abstractos de datos: Ejemplos (2)
Definición del tipo de datos “COMPLEJO” en ANSI C:
Definición del tipo de datos “COMPLEJO” en ANSI C:
archivo complejos.h:
archivo complejos.c:
typedef struct
#include “complejos.h”
{
float real;
float imag;
} COMPLEJO;
int c_equal(COMPLEJO x,
COMPLEJO c_add(COMPLEJO
COMPLEJO c_sub(COMPLEJO
COMPLEJO c_mul(COMPLEJO
COMPLEJO c_div(COMPLEJO
/* fin de complejos.h */
int c_equal(COMPLEJO x, COMPLEJO y)
{
return
((x.real == y.real) && (x.imag == y.imag));
} /* c_equal */
... siguen las demás operaciones....
COMPLEJO y);
x, COMPLEJO y);
x, COMPLEJO y);
x, COMPLEJO y);
x, COMPLEJO y);
97
Mecanismos de paso de parámetros
Recursividad
por valor:
antes - llamada - después
A:
-5
b:
0
b=abs(A)
A:
-5
b:
5
Mecanismo por el cual un procedimiento puede autoreferenciarse.
,
al
Ejemplo:
er
subrutina:
function abs(x: integer)
begin
if x < 0 then
return -x
else
return x
end
A:
-5
b:
0
b=abs(A)
A:
5
b:
5
subrutina:
function abs(var x: integer)
begin
if x < 0 then
return -x
else
return x
end
99
Rutinas Re-entrantes
o
tiv
ra
ite
o te
t
n
ie len
im iva
ed qu
c
e
o
Pr
100
Consiste en la capacidad de asignar memoria a un
proceso durante la ejecución del mismo.
Necesaria para la construcción y mantenimiento de los
stacks necesarios en cualquier SO de tiempo real.
Alternativa: stacks de tamaño fijo: debo conocer de
antemano su tamaño máximo.
Compromiso:
USO EFICIENTE
DEL RECURSO
MEMORIA
int flag=0; */ var. global */
int no_reentrante()
{
printf(¨flag vale %i¨, flag);
if (flag == 0)
func1(); flag = 1;
else
func2(); flag = 0;
}
void mcd(int x,y);
{
int z;
while (y != 0){
z=y;
y=x % y;
x=z;
}
printf(”mcd = %d”,x);
}
Asignación dinámica de memoria
Una rutina re-entrante es aquella que puede ser
utilizada por varias tareas que se ejecutan en forma
concurrente, en un sistema multitarea.
Un lenguaje de programación permite escribir
rutinas re-entrantes, pero que una rutina lo sea o
no depende del programador!
Ejemplo :
n
ge !
en te!
o, ien
r
pe fic
te ine
an uy
g
e m
El
void mcd(int x,y);
{
if (y == 0)
printf(”mcd = %d”,x);
else
mcd(y, (x % y) );
}
por referencia o por dirección:
antes - llamada - después
98
101
vs.
USO EFICIENTE
DEL RECURSO
CPU
102
17
Asignación dinámica de memoria
Modularidad
Funciones en C para reserva y liberación de memoria:
malloc() reserva memoria
free() la libera
PASCAL: sentencias NEW y DISPOSE
Alternativa a la administración manual de memoria:
“Garbage Collection”, usual en lenguajes orientados a
objetos tales como Eiffel, JAVA y Smalltalk
103
Modularidad
Consiste en dividir al software en componentes con
nombres y ubicaciones determinados, que se denominan
módulos y que se integran para satisfacer los requisitos
del problema.
Sea:
C(p): complejidad del problema p
E(p): esfuerzo requerido para resolver el problema p
Evidencias empíricas:
C(p1) > C(p2) => E(p1) > E(p2)
C(p1 + p2) > C(p1) + C(p2)
Si el número de módulos crece mucho, entonces el
esfuerzo asociado con el manejo de sus interfaces
compensa la ventaja de particionar el problema en 104
módulos!
Orientación a Objetos
Modularidad y Lenguajes de Programación:
Un Módulo debe ser compilable separadamente
Un Módulo consta de:
una interfaz pública
de
pue es
una realización privada
ón
d
aci ieda ho de
m
p
ro
ec
gra
Ejemplo: “Package” de ADA
p r o a s p lo h ! !
en l so rlo!
de
a je r b u r o e g r a
ngu logra d, pe ara lo
e
l
Un dar a larida za p
n
ayu modu alca
d e r lo n o
a
us
105
Manejo de excepciones
Definición: Un
sistema de
software orientado
a objetos es aquel
que está construido
como una
colección
estructurada
de realizaciones de
tipos abstractos de
datos.
cada mó
módulo será
será la realizació
realización de un tipo abstracto
de datos, que se denomina CLASE.
Las clases son unidades autó
autónomas, que colaboran
para lograr satisfacer los requerimientos del sistema
Existen relaciones entre las clases, a saber:
• CLIENTECLIENTE-SERVIDOR
• HERENCIA
Polimorfismo: posibilidad de definir una función
que tenga distintos efectos según el tipo de objeto
a que se le aplique.
Ejemplos :
C++
Smalltalk
Eiffel
Java
Ada95
OO y Tiempo Real:
Real
• dynamic binding
• garbage collection
106
1.- Lenguaje Ensamblador (Assembler)
Existen lenguajes que ofrecen facilidades para expresar
cómo debe reaccionarse frente a un error u otra condición
anormal que se dé durante la ejecución del programa.
Estas situaciones se llaman EXCEPCIONES
El código invocado si ocurre una excepción se llama
rutina de atención a la excepción (“exception handler”)
Algunas excepciones están previstas (y son detectadas)
por el propio microprocesador. El programador debe
suministrar la rutina de atención a la excepción.
Ejemplo: división por cero
Ejemplo de lenguajes que tienen previsto el tratamiento
de excepciones: ADA, Eiffel, JAVA.
107
No posee casi ninguna de las
características discutidas, que
son propias de los lenguajes
de alto nivel
no estructurado
inherentemente no portable
difícil de aprender, tedioso,
favorece errores
La existencia de buenos
compiladores hace que en
general se obtengan
programas más eficaces si se
escriben en lenguajes de alto
nivel que “optimizando
assembler a mano”
Provee control directo sobre el
hardware
Puede ser la única manera de
optimizar al máximo una
pequeña rutina que tiene gran
incidencia en la respuesta
temporal del sistema.
En sistemas muy pequeños
(ej: Microcontroladores de 8
bits), puede ocurrir que los
recursos necesarios para usar
un lenguaje de alto nivel no
estén disponibles.
108
18
2.- Lenguaje PASCAL (estándar)
Diseñado en 1968 para
enseñar programación, no
para uso profesional!!!
No posee variables estáticas
Standard I/O es defectuosa y
no se puede sustituir (el
estándar es cerrado)
No posee elementos que
permitan la construcción de
programas grandes. En
particular, carece de la noción
de módulo compilable
separadamente
No es fácilmente extensible
3.- Lenguaje C
Lenguaje Elegante y Simple,
ideal para enseñar
programación estructurada.
Estándar ANSI/IEEE
tipificación de datos fuerte
recursión
estructuras de datos
dinámicas
tipos enumerados
fomenta la estructuración de
los programas
(“GOTO” considered harmful)
(estas son algunas de las críticas
formuladas por Kernigham, uno de los
No ayuda a seguir los
principios de la ingeniería de
software: en C “está todo
permitido”
Manejo de punteros es difícil
de aprender y provoca
numerosos errores, aún entre
programadores
experimentados.
No existen chequeos
automáticos (por ejemplo, del
índice de un array)
control de tipos muy débil
109
autores del lenguaje C)
4.- Lenguaje ADA
Sólo es utilizable en sistemas
que disponen de una cierta
cantidad de recursos
No existen compiladores de
costo accesible para todas las
plataformas
Lenguaje más bien extenso,
difícil de comprender y aprender
en su totalidad
La introducción de la orientación
a objeto en ADA95 aparece
como un tanto forzada
La condesa Ada Augusta Byron (Ada
Lovelace) fue matemática y la única hija
legítima del poeta Lord Byron.
Trabajó con Charles Babbage en su
Máquina de Diferencias, y es
considerada la primera programadora de
la historia. Lady Lovelace murió en 1852
a la edad de 36 años.
Estandarizado, existen
compiladores de dominio
público para cualquier
plataforma hardware
importante
No es paternalista: en C
“está todo permitido”
asignación dinámica de
memoria
compilación separada de
módulos
Actualmente, es “el”
lenguaje de programación
para aplicaciones de tiempo
real no militares.
110
5.- Lenguaje JAVA
Estandarizado
Promueve la creación de programas
confiables: Confiabilidad
tipificación fuerte
run-time checkings
Soporta muy bien la modularidad
separación de especificación y
realización de los módulos
módulos y packages compilables por
separado
Promueve un buen estilo de
programación: Tipos abstractos de
datos, Manejo de excepciones
Específicamente diseñado para
aplicaciones de tiempo real.
Primitivas de sincronización de 111
tareas
Solo es utilizable en sistemas
que disponen de una cierta
cantidad de recursos
La “máquina virtual de JAVA”
no está disponible (aún?) para
todas las plataformas
Los compiladores actuales
producen código muy
ineficiente
Orientado a objetos, Simple
Ambientes de desarrollo en el
dominio público
Suprime aspectos más polémicos
de C++ manteniendo su sintaxis
básica
Lenguaje de la “era internet”
tipificación mucho más fuerte que
C, C++
run-time checkings
aborda el problema de privacidad
multi-tareas, sincronización y
comunicación entre tareas
manejo de excepciones
garbage collection
112
Programación Concurrente
Nombre dado a la notación y técnicas de
programación que permiten expresar el
paralelismo potencial y resolver los problemas
resultante de sincronización y comunicación.
Programación
concurrente
La implementación (hardware y software) del
paralelismo es un tema esencialmente
independiente de la programación concurrente.
113
La programación concurrente proporciona una
visión abstracta para estudiar el paralelismo sin
entrar en los detalles de su implementación.
114
19
¿Porqué es necesaria?
¿Porqué es necesaria?
Para modelar el paralelismo en el mundo real
Para permitir la expresión del paralelismo
potencial de tal forma que se pueda emplear
más de un computador para resolver el
problema.
Virtualmente, todos los sistemas de tiempo real
son concurrentes por naturaleza.
Las actividades en el mundo real evolucionan
simultáneamente.
Para maximizar la utilización del procesador
Esta es la principal razón para usar
concurrencia
115
116
Terminología
¿Porqué es necesaria?
Una alternativa consiste en utilizar técnicas de programación
secuencial
El programador debe construir el sistema de tal manera que
implique la ejecución cíclica de una secuencia de programa para
gestionar varias actividades concurrentes.
Esto complica la ya de por sí difícil tarea del programador e
implica la consideración de estructuras que son irrelevantes para
el control de las actividades que tiene entre manos.
Los programas resultantes son más oscuros y menos elegantes
Complica la descomposición del problema
La ejecución paralela del programa en más de un procesador
podría ser mucho más difícil de conseguir.
La escritura de código para el tratamiento de fallos es más
problemático.
Procesos concurrentes: Se dice que dos o más procesos
son concurrentes si pueden ejecutarse en paralelo, de
forma que alguno de ellos comience a ejecutarse antes que
termine algún otro.
Programa concurrente: Conjunto de procesos
secuenciales autónomos, que se ejecutan (lógicamente) en
paralelo o, de forma equivalente, un programa cuya
ejecución se realiza según varios flujos de control que
avanzan en paralelo.
Cada proceso tiene su propio flujo de control. A veces se habla de
procesos con varios flujos de control (threads)
Las instrucciones de los procesos se ejecutan intercalándose unas
con otras (paralelismo lógico)
117
Terminología
118
Concurrencia
La ejecución de la colección de procesos concurrentes
se puede realizar de tres formas:
Los elementos empleados en la programación
concurrente deben permitir:
la creación de procesos concurrentes
la sincronización de procesos
la comunicación entre procesos
Multiprogramación: Un único procesador va alternando la
ejecución de los diversos procesos (entrelazado)
Multiprocesamiento: Cada proceso se ejecuta en un procesador
diferente con acceso a una zona de memoria común (datos
comunes). Sistema fuertemente acoplado
En función de la interacción (sincronización y
comunicación ) entre procesos estos pueden ser:
Procesamiento distribuido: Los procesos multiplexan su ejecución
en varios procesadores que no comparten memoria.
119
Independientes : no se comunican ni sincronizan
Cooperativos: para realizar alguna acción común
Competitivos: para acceder a recursos compartidos
Los procesos que cooperan o compiten necesitan
120
comunicarse y sincronizar sus actividades
20
Ejecución concurrente
Ejecución concurrente
Características del modelo de concurrencia:
Características del modelo de concurrencia:
Estructura
Inicialización (información relacionada con su ejecución)
Estática:
nº de procesos fijo conocido a priori en tiempo de
compilación
creación dinámica en tiempo de ejecución
Dinámica:
Nivel de paralelismo
Anidado:
los procesos se definen en cualquier nivel. Se
pueden definir procesos dentro de otros procesos,
lo que permite crear jerarquías de procesos
los procesos se definen en el nivel más externo del
programa.
Plano:
Granularidad
Grueso:
pocos procesos de larga duración con gran
variedad de acciones
muchos procesos sencillos y efímeros
Fino:
Por paso de parámetros en la creación del proceso
Comunicación explícita (IPC) con el proceso una vez creado
Finalización del proceso
Por llegar al final del cuerpo del proceso
Suicidio por ejecución de una sentencia de autofinalización
Aborto mediante una acción explícita de otro proceso
Ocurrencia de una condición de error (excepción) sin manejar
Nunca (bucle infinito)
Cuando ya no son necesarios (si no tiene procesos
dependientes de él)
121
122
Ejecución concurrente
Jerarquía y relaciones entre procesos
Para un proceso, es útil distinguir entre el proceso (o
bloque) que es responsable de su creación, y el proceso
(o bloque) que es afectado por su finalización.
Relación padre/hijo
Un proceso (padre) crea a otro (hijo)
El padre ha de esperar mientras el hijo se crea e inicializa
Sincronización y
comunicación
Relación tutor/pupilo o guardián/dependiente
Un proceso (pupilo) puede depender del propio proceso tutor o
de un bloque interno de éste.
El tutor no puede terminar hasta que todos los procesos
dependientes él (pupilos) hayan terminado
El tutor puede ser: el padre, otro proceso o un bloque interno del
padre o de otro proceso.
123
Sección Crítica y Exclusión Mutua
Propiedades de la Sincronización
Ausencia de deadlocks (bloqueos)
Condiciones necesarias para un deadlock:
Cola de Impresión:
Proc A
124
abc.txt
4
5
ejemp.ps
6
ejemp2.ps
7
los procesos pretenden acceso exclusivo a los recursos
(mutual exclusion condition)
los procesos mantienen los recursos obtenidos mientras
esperan por otros (wait for condition; only serially
reusable resources)
a los procesos no se les puede quitar un recurso hasta
que ellos lo liberen voluntariamente (no preemption
condition)
existe una cadena cerrada de procesos y recursos, en la
cual los procesos esperan por recursos que están siendo
ocupados por otro proceso (circular wait condition)
out = 4
in = 7
Proc B
SECCIÓN CRÍTICA: secuencia de instrucciones que
debe ser ejecutada indivisiblemente
EXCLUSIÓN MUTUA: sincronización necesaria para
proteger una sección crítica
125
126
21
Propiedades de la Sincronización
Propiedades de la Sincronización
Ausencia de livelocks (inanición)
Ejemplo:
Se inician las tareas en orden A, B, C.
Los recursos se obtienen todos juntos, o no se obtienen
el proceso B tiene un livelock por la conspiración de A y C:
Ejemplo de Deadlock:
Cruce de dos calles
• sin semáforos
• única regla de preferencia:
“pasa primero el que
viene por la derecha”
Tarea A
Tarea B
Tarea C
Solicitar Lector
Solicitar Lector e
Impresora
Solicitar Impresora
Lector Asignado
Lector e Impresora Asignados
Impresora Asignada
Imprimir 10 Formularios
Leer 100 Unidades
Leer 200 Unidades
Liberar Lector
Imprimir 5 Formularios
Liberar Impresora
Liberar Lector e Impresora
127
Respetar las capacidades límites
– no sacar, cuando está vacío
– no poner, cuando está lleno
(PROBLEMA PRODUCTOR/CONSUMIDOR)
R1
R1
P1
P1
R2
R2
P2
P3
128
P2
R3
P3
R3
129
Entrelazado
130
Entrelazado
Entrelazado y operaciones atómicas
Proceso P ;
x,y: entero ;
Proceso Q ;
z,u: entero ;
P1: x:=1 ;
P2: y:=x+2 ;
Q1: z:=3 ;
Q2: u:=z+1 ;
fin P ;
fin Q ;
Cada instrucción de alto nivel: varias instrucciones
código máquina.
Por ejemplo: x := y + z ;
copiar
copiar
sumar
copiar
Posibles ejecuciones:
(P1; P2; Q1; Q2)
(P1; Q1; P2; Q2)
(Q1; P1; P2; Q2)
...
y, r1
z, r2
r1, r2
r2, x
Operaciones atómicas.
131
132
22
Comunicación y Sincronización
Compartición de una variable
La dificultad de la programación concurrente estriba en
las interacciones de los procesos:
Ejemplo: dos procesos (contador y escritor) comparten
una variable n.
Cooperación para un fin común
Competencia por el uso de recursos
VARIABLE COMPARTIDA
n : entero := 0;
Son necesarias operaciones de comunicación y
sincronización entre procesos:
proceso contador;
principio
repetir
esperar pulso;
n:=n+1;
fin repetir;
fin;
Sincronización: cumplir restricciones sobre el orden en el
que se ejecutan sus acciones
Comunicación: paso de información de un proceso a otro
proceso escritor;
principio
repetir
esperar 1 hora;
escribir n;
n:=0;
fin repetir;
fin;
Hay dos formas de realizarlo:
ERROR: el resultado depende del orden
en que se intercalen las instrucciones
Datos compartidos
Paso de mensajes
133
Compartición de una variable
Compartición de una variable
Posibles trazas:
Sección crítica: Se garantiza que dos procesos no
estarán ejecutando a la vez una misma región crítica
(escribir n; n:=0; n:=n+1)
(escribir n; n:=n+1; n:=0) --> Pérdida de pulso
(n:=n+1; escribir n; n:=0)
n := n + 1 ;
copiar
sumar
copiar
n, r1
r1, 1
r1, n
134
Monitores, mutex, Test_and_set
Ejemplo: dos procesos (contador y escritor) comparten
una variable n.
VARIABLE COMPARTIDA
n : entero := 0;
/ (escritor) n:=0;
=> Pérdida de la puesta a cero de n
Problema: entrelazado de las instrucciones en el
acceso a la variable común.
Solución: garantizar la exclusión mutua en el acceso al
elemento compartido.
135
Exclusión mutua
proceso contador;
principio
repetir
esperar pulso;
region n hacer
n:=n+1;
fin;
fin repetir;
fin;
proceso escritor;
principio
repetir
esperar 1 hora;
region n hacer
escribir n;
n:=0;
fin;
fin repetir;
fin;
136
Sección crítica no expulsable
Evitar expulsiones cuando se ejecuta una sección crítica
Dos procesos compiten cuando comparten:
Enmascarar interrupciones
un recurso
una variable (comunicación)
No entra el núcleo, ni el reloj, ...
Elevar al máximo la prioridad del código
Posibilidad de cambiar en tiempo de ejecución la prioridad
de un tarea
El acceso al recurso o a la variable debe ser en
exclusión mutua.
Sección crítica: secuencia de instrucciones que debe
ejecutarse en exclusión mutua
Mecanismos de sincronización
Espera ocupada (busy waiting)
Semáforos
Monitores
137
void Servicio (...) {
Mask_all_Interrupts () ;
Service_Code() ; /* sección critica */
Unmask_all_Interrupts () ;
return ;
void Servicio (...) {
}
Nominal = Get_Priority () ;
Set_Priority (HIGH) ;
Service_Code() ; /* sección critica */
Set_Priority (Nominal) ;
return ;
}
138
23
Espera ocupada (Busy waiting)
Exclusión Mutua - “busy waiting”
Puede usarse un indicador compartido si el acceso al
mismo es atómico
Problema:
Test_and_Set: operación atómica que bloquea un
indicador y devuelve el valor que tenía antes
INDICADOR COMPARTIDO
proceso P1;
Bloqueado: booleano:= false;
principio
repetir
mientras Test_and_Set(Bloqueado)
nada;
fin mientras;
< sección crítica >
Bloqueado := false ;
< otras cosas >
Test_and_Set:
fin repetir;
load r1, 1
atómica
fin ;
swap r1, flag
return r1
139
Exclusión Mutua - “busy waiting”
Características de la solución
no asumir orden fijo de ejecución
un proceso fuera de su sección crítica no debe bloquear
a otros procesos
ningún proceso debe esperar indefinidamente para
entrar en su sección crítica
140
Exclusión Mutua - “busy waiting”
Ejemplo:
Solución 1:
Quien está saliendo iza una bandera con el número de la
persona que puede entrar
2 personas quieren acceder a un ÁREA CRÍTICA con
exclusividad.
Desde fuera no se puede saber si el área crítica está
ocupada, pero existen garitas desde las cuales se
pueden ver banderas que se utilizan dentro del área
crítica para pasar información.
Garita 1
Análisis de la solución
Satisface requerimiento de exclusión mutua
No hay posibilidad de deadlocks
No hay posibilidad de livelocks (asumiendo estancia finita
en área crítica)
Procesos fuertemente entrelazados (se “van pasando” el
derecho a entrar)
persona1
ÁREA CRÍ
CRÍTICA
Garita 2
loop
<prot. entrada>
<sección crít.>
<prot. salida>
<sección no
crítica>
ventanas
secuencia estricta de entrada: una vez cada uno
si un proceso termina, el otro queda en deadlock.
141
Exclusión Mutua - “busy waiting”
142
Exclusión Mutua - “busy waiting”
Solución 1:
Solución 2:
Quien está saliendo iza una bandera con el número de la
persona que puede entrar
Objetivo: Evitar los problemas de solución 1
Cada persona tiene su propia bandera, para que la ponga
en la garita. Para entrar P1:
Análisis de la solución
Loop de persona1:
flag !=1
ÁREA CRÍ
CRÍTICA
esperar
<sección crít.>
flag = 2
<sección no crítica>
1/2
Garita 1
Dos tareas requieren la utilización exclusiva de un
recurso
¿Cómo garantizar que en el tiempo que transcurre
desde que una tarea consulta si el recurso está siendo
utilizado hasta que lo comienza a utilizar, este recurso
no es tomado por la otra tarea?
alza su bandera (1) para indicarlo
LUEGO chequea el estado de la bandera del otro lado (2)
si (2) está baja, entra al área crítica, y al salir baja su bandera.
si (2) está alta, se queda en la garita esperando hasta que P2
salga, y entonces entra
Análisis de la solución
La solución no está libre de deadlocks!
¿En qué caso?
Garita 2
143
144
24
Exclusión Mutua - “busy waiting”
Exclusión Mutua - “busy waiting”
Solución 2:
Solución 3 (Algoritmo de Dekker):
Objetivo: Evitar el deadlock de la solución anterior
Se agrega una bandera de prioridad que se usa solo en el
caso que ambas personas soliciten entradas simultáneamente
(en otro caso, vale la solución 2).
La bandera de prioridad indica cuál de las 2 personas tiene
prioridad para insistir.
Análisis de la solución
La solución no está libre de deadlocks!
¿En qué caso?
Loop de persona1:
Análisis de la solución
flag1 = UP
flag2 == UP
esperar
<sección crít.>
flag1 = DOWN
<sección no crítica>
ÁREA CRÍ
CRÍTICA
1
entra a la zona crítica.
al salir cambia el No. en la bandera de prioridades.
Solución elegante de la exclusión mutua, sin utilizar primitivas
especiales.
Protocolos difíciles de diseñar, entender y verificar (probar
extender esto para más de 2 tareas)
Busy wait
...
2
Garita 1
Garita 2
145
Exclusión Mutua - “busy waiting”
Semáforo
Solución 3 (Algoritmo de Dekker):
Es una variable que toma valores enteros no negativos
(counting semaphore)
Análisis de la solución
...
proceso “perverso” puede utilizar mal las variables compartidas y
corromper todo el sistema
Se ha asumido que entre chequear el estado de una bandera y entrar
al área de exclusión no ocurre nada!
Loop de persona1:
prio = 2
ÁREA CRÍ
CRÍTICA
1
1
Bandera de
prioridad
2 Garita 2
esperar
<sección crít.>
flag1 = DOWN
<sección no crítica>
147
Sincronización condicional
148
La exclusión mutua puede asegurarse con un semáforo
binario, inicializado a uno
mutex (MUTual EXclusion)
mutex: semaphore := 1 ;
proceso P1;
proceso P2;
principio
principio
repetir
repetir
Wait(mutex) ;
Wait(mutex) ;
<sección crítica>
<sección crítica>
Signal(mutex)
Signal(mutex)
<sección no crítica>
<sección no crítica>
fin repetir;
fin repetir;
fin P1 ;
fin P2 ;
condicion: semaphore := 0 ;
proceso P2; -- avisa
principio
repetir
<parte 2a>
Signal(condicion)
<parte 2b>
fin repetir;
fin P2 ;
La parte 1b no se ejecuta hasta que P2 avisa que se cumple la
condición necesaria
Las operaciones signal y wait son atómicas.
Los semáforos tienen asociada una cola de
procesos suspendidos en espera.
Los semáforos son gestionados por el núcleo de
ejecución
Semáforo: exclusión mútua
Sincronización condicional: una acción de un proceso
sólo se puede ejecutar si otro proceso está en un cierto
estado o si ha ejecutado ciertas acciones.
Un semáforo binario inicializado a cero sirve para
comunicar que se cumple la condición
proceso P1; --espera
principio
repetir
<parte 1a>
Wait(condicion) ;
<parte 1b>
fin repetir;
fin P1 ;
S : semaphore := valor_inicial ;
wait(S):
si S > 0, S := S - 1
si no, suspender el proceso
signal(S):
si hay procesos esperando,
pasar uno de ellos a preparado
si no, S := S + 1
flag1 = UP
flag2 == UP
&& prio ==2)
Garita 1
146
149
CUIDADO: si un proceso olvida liberar
el mutex, el recurso queda bloqueado
150
25
Semáforo: exclusión mútua
Cuidado con los bloqueos
Cuando se comparten recursos entre procesos, es
posible que aparezcan bloqueos mutuos:
SNC
recurso1, recurso2: semaphore := 1 ;
proceso P1;
proceso P2;
SNC
wait
wait
SC
SC
Wait(recurso1) ;
Wait(recurso2) ;
....
Signal(recurso2) ;
Signal(recurso1) ;
Wait(recurso2) ;
Wait(recurso1) ;
....
Signal(recurso1) ;
Signal(recurso2) ;
Bloqueo
mutex
proceso P1;
signal
proceso P2;
signal
SNC
Wait(recurso1) ;
Wait(recurso2) ;
....
Signal(recurso2) ;
Signal(recurso1) ;
SNC
151
Comunicación
Wait(recurso1) ;
Wait(recurso2) ;
....
Signal(recurso2) ;
Signal(recurso1) ;
152
Correcto
Productor/consumidor
Buffer Ilimitado
Buffer Limitado
Productor
Consumidor
buffer
153
Productor/consumidor
154
Lectores/escritores
Buffer Limitado
Productor
Consumidor
Lector1
2
Escritor1
2
2
buffer
Lector2
Escritor2
2
tamaño
155
Problema : inanición de los escritores
156
26
Lectores/escritores
Semáforos: RESUMEN
Ventajas
Escritor1
Mecanismo simple y eficiente
Permite exclusión mutua y sincronización condicional
Evita las esperas ocupadas (busy waiting)
Lector1
Inconvenientes
2
Mecanismo de bajo nivel: poco estructurado
Su uso queda disperso por los procesos
Es fácil cometer errores: un solo wait o signal mal
colocado puede ser fatal
Es mejor utilizar mecanismos más abstractos y fiables
como los monitores
Lector2
2
Escritor2
157
Monitor
158
Monitor
Es un módulo que encapsula las secciones críticas
asociadas a una variable o un dispositivo físico en forma de
procedimientos que son llamados por los procesos
Sólo se puede acceder al
elemento compartido a
través de los procedimientos
del monitor
Las llamadas a los
procedimientos del monitor
se ejecutan en exclusión
mutua.
Monitor Contador;
n: entero := 0 ;
Hay lenguajes que soportan monitores
ej: protected de Ada 95
Pueden programarse
mediante semáforos
/* fichero contador.h */
procedimiento incrementa;
principio
n:=n+1;
fin;
void incrementa(void) ;
void escribe_borra(void) ;
procedimiento escribe_borra;
principio
escribir n;
n:=0;
fin;
fin Contador ;
159
Exclusión mutua e interrupciones
/* fichero contador.c */
#include “contador.h”
#include <semaphore.h>
/* variables privadas del monitor */
static semaphore mutex_contador ;
static int n = 0 ;
void incrementa(void) {
wait(mutex_contador) ;
n:=n+1;
signal(mutex_contador) ;
}
void escribe_borra(void) {
wait(mutex_contador) ;
escribir(n);
n:=0;
signal(mutex_contador) ;
}
160
Comunicación mediante mensajes
Las rutinas de servicio de interrupciones (ISR) se
ejecutan en concurrencia con el resto de procesos.
Las tareas se pueden comunicar o sincronizar mediante
paso de mensajes
No requiere memoria compartida
Exclusión mutua => inhibir interrupciones
Puede usarse en sistemas distribuidos
static int n = 0 ;
Según el tipo de sincronización emisor-receptor:
void rutina_interrupcion(void) {
n:=n+1;
}
Comunicación asíncrona (buzón, semáforo)
El emisor envía el mensaje y continúa
Comunicación síncrona (cita)
void escribe_borra(void) {
inhibir_interrupciones() ;
escribir(n);
n:=0;
activar_interrupciones() ;
}
El emisor espera a que el receptor reciba el mensaje
Invocación remota (cita extendida)
El emisor espera a que el receptor reciba el mensaje, lo procese y
envíe una respuesta
161
162
27
Comunicación
Buzón
Comunicación asíncrona o por mensajes
Un proceso P produce y envía una secuencia de datos a
otro proceso C que los recibe y consume. Los datos son
transmitidos en porciones discretas denominadas
mensajes.
Es posible que P produzca un mensaje cuando C no esté
en disposición de recibirlo. Para evitar que P espere se
introduce un área de almacenamiento de mensajes donde P
puede colocar sus mensajes hasta que C los lea: BUZON o
COLA DE MENSAJES
Emisor
Así
Asíncrona
Receptor
Síncrona
P
Invocació
Invocación
remota
163
Buzón
B
C
Es posible que un buzón tenga varios procesos emisores y
164
varios receptores.
Buzón: ejemplos de uso
Manejo de buzones:
Desacoplar una tarea rápida de una tarea lenta
Buzón
B : buffer
send(M,B)
max
of
T
Tarea
Control
receive(M,B)
La política de manejo de un buzón puede ser:
Tarea
Pantalla
Servidor con varios clientes
Si al enviar un mensaje el buzón está lleno:
Las peticiones indican el buzón de respuesta
Buzones
el emisor espera hasta que haya espacio
el emisor espera, con un tiempo máximo
el mensaje se descarta
se descarta otro mensaje (p.ej. el más antiguo)
Respuestas
Tarea
Cliente 1
Si al solicitar un mensaje el buzón está vacío:
el receptor espera hasta que haya mensaje
el receptor espera, con un tiempo máximo
se le indica que no hay mensaje y puede continuar
Avisos
Peticiones
Tarea
Servidor
Tarea
Cliente 2
165
Respuestas
166
Uno de los aspectos más relevantes que debemos tener
en cuenta a la hora de desarrollar sistemas de tiempo
real es el sistema operativo o núcleo ejecutivo.
El sistema operativo debe proporcionar soporte básico
para tareas de tiempo real, tolerancia a fallos,
predictibilidad, etc.
Sistemas operativos
167
168
28
Los actuales sistemas operativos de tiempo real:
Para garantizar las especificaciones temporales:
poseen un cambio de contexto rápido,
poseen un reloj de tiempo real,
poseen un tamaño adaptable a la aplicación que se desea
desarrollar pudiendo llegar a un sistema mínimo con una
funcionalidad restringida,
proporcionan mecanismos de planificación basados en prioridades,
proporcionan alarmas y timeouts, y
las tareas pueden hacer uso de llamadas para bloquearse durante
determinados intervalos de tiempo.
responden a las interrupciones externas de una forma rápida,
minimizan los tiempos en los que las interrupciones están
deshabilitadas,
proporcionan esquemas de gestión de memoria basados en
particiones fijas o particiones variables (nunca memoria virtual
para tareas con restricciones estrictas de tiempo real)
proporcionan archivos especiales que son capaces de
almacenar datos a gran velocidad.
169
Componentes del sistema informático
170
Componentes del sistema informático
Sistema Informático de propósito general
S.O.
Aplicaciones del usuario
Hardware - proveé los componentes básicos de cómputo
(CPU, memoria, dispositivos de E/S).
Sistema Operativo - controla y coordina el uso del hardware
Soporte
entre los varios programas de aplicación para los diferentes
usuarios.
Programas de Aplicación - define las formas en que los
recursos del sistema son utilizados para resolver los problemas
de cómputo de los usuarios (compiladores, bases de datos,
juegos de video, programas de negocios).
Usuarios (gente, máquinas, otras computadoras).
de
lenguaje
SW
HW
Utilidades
Gestión de ficheros
PlanifiSubsist.
Despa- Gestión cador
E/S chador de INT
CPU
171
172
E/S
Objetivos del S.O.
Gestión de tareas: (Scheduling) asignación de tiempo de procesador
a las tareas. Decide que tarea pasa a ejecutarse.
Gestión de memoria: control de asignación de memoria.
Gestión de recursos: Controla los recursos compartidos diferentes a
memoria y tiempo de procesador. Almacena la información asociada a
los recursos compartidos por parte de las tareas. Se refiere a los
canales de comunicación entre tareas.
Sistemas operativos de
tiempo real (SOTR)
Gestión y comunicación entre tareas. Suministra los mecanismos
que dan soporte a la comunicación segura entre tareas y a la
sincronización de sus actividades. Creación de tareas y
mantenimiento de la información asociada a tareas, así como la
eliminación de esta información. Una tarea puede crearse por
invocación de otras tarea
173
174
29
Sistema operativo mínimo
No se trata de que los SOTR sean sistemas rá
rápidos sino
de que sean fiables.
S.O.
debe satisfacer las restricciones temporales explícitas de modo que
si no se cumpliesen, se darían en el sistema consecuencias de
riesgo severo incluso el fallo total
diseñar el SOTR pensando más en el peor caso que en optimizar el
Software de aplicación
rendimiento medio.
atender con una alta prioridad a las señales externas (interrupciones)
provenientes del sistema , ya que pueden informarnos de un cambio
de estado en el sistema.
minimizar todo aquello que conlleve un alto precio en el tiempo de la
CPU
Kernel o
núcleo
SW
HW
CPU
E/S
175
El núcleo (kernel) de un SOTR
El núcleo (kernel) de un SOTR
Requisitos generales para el kernel subyacente en un SOTR:
Funcionalidades generales incluidas en los kernels de sistemas
empotrados para aplicaciones específicas de TR:
Multitarea.
Planificación (Scheduling) por desalojo.
Cambio de contexto rápido.
Tamaño pequeño.
Rapidez y flexibilidad en la comunicación y sincronización entre tareas.
Facilidad de comunicación entre tareas y niveles de interrupción.
Capacidad de responder rápidamente a interrupciones externas.
Límite de ejecución.
Dotación de particiones fijas o variables para la gestión de memoria
Minimizar los intervalos durante los que las interrupciones están
deshabilitadas.
Capacidad de bloquear acceso al código o a datos de memoria.
El kernel ha de mantener un reloj de tiempo real.
177
Requisitos actuales de los SOTR
Determinismo
Capacidad para responder a sucesos rápidamente
Control del sistema por parte del usuario
Gestión de prioridades
Fiabilidad
Gestión de Memoria
Comunicación entre tareas
Código Reentrante
Tamaño reducido de código
SOTR distribuidos
Configurabilidad
Adaptabilidad
Gestión eficiente de recursos.
Planificación (Scheduling) de tareas y comunicaciones.
Multitarea con baja sobrecarga por cambios de contexto.
Equilibrado de carga de trabajo.
Reconfiguración y recuperación dinámica.
Operación de dispositivos.
E/S síncrona y asíncrona.
Respuesta rápida a interrupciones externas.
Primitivas IPC (memoria compartida, semáforos, eventos asíncronos).
Posibilidad de bloqueo y desbloqueo de memoria.
Uso limitado de memoria virtual.
Soporte de tiempo real para cumplimiento de plazos de respuesta:
planificación basada en prioridades, relojes de tiempo real, alarmas
especiales, primitivas para retardar, parar o reanudar tareas, etc.
Tamaño ajustable a las necesidades de empotramiento.
176
178
Requisitos actuales de los SOTR
Determinismo
tendencia que tiene el sistema a realizar una determinada
acción en un tiempo predefinido. El minimizar el tiempo de
respuesta a interrupciones garantiza un mayor nivel de
determinismo.
Capacidad para responder a eventos rápidamente
distinguiendo entre sucesos síncronos y asíncronos. Necesita
una rutina de interrupciones para dar una respuesta
“inmediata” a los sucesos asíncronos. Requiere que el
desalojo y realojamiento de procesos de la CPU se haga con
rapidez.
Control del sistema por parte del usuario
179
de modo que los usuarios puedan conmutar entre distintos
modos de ejecución. Por ejemplo, un operario que acciona un
botón de emergencia de una máquina.
180
30
Requisitos actuales de los SOTR
Requisitos actuales de los SOTR
Gestión de prioridades
Gestión de Memoria
En los sistemas operativos tradicionales la prioridad es
dinámica, el propio sistema operativo va incrementando o
decrementando la prioridad conforme pasa el tiempo. En los
SOTR la prioridad debe ser estática con prioridades
determinadas, al menos para varios procesos especialmente
críticos. Las interrupciones procedentes del exterior tienen
una prioridad fija, que no depende de tiempos de espera o
ejecución. Además, se ha de analizar si la tarea se realiza
según los plazos (seguimiento preventivo y predictivo) y
cómo interfiere con las demás
ha de ser más estricta que en los sistemas operativos
tradicionales. Cuanta mayor facilidad se trata de dar al
usuario mayor va a ser el kernel. En los SOTR el kernel debe
ser lo menor posible.
Comunicación entre tareas
debe ser muy rápida. Suele ser explícita, la tiene que hacer
el usuario.
Código Reentrante
se refiere a la posibilidad de que dos procesos puedan
emplear un mismo código de programa, sin tener que tener
una copia del mismo para cada uno y sin que haya
problemas de interferencias entre ellos al manejar el mismo
código.
Fiabilidad
en caso de fallo hardware ha de haber una solución de tipo
software. Deben estar contempladas todas las respuestas
que daríamos a cada uno de los posibles fallos que se
pudiesen dar.
181
Requisitos actuales de los SOTR
182
Requisitos actuales de los SOTR
Tamaño reducido de código
Configurabilidad
conviene que el repertorio de rutinas empleado sea lo menor
posible, a costa de mayor coste de programación por parte
del usuario, de modo que se minimice el número de
primitivas y el kernel.
Consiste en que el SOTR sirva para una amplia gama de
sistemas: desde pequeños sistemas empotrados hasta
sistemas donde cada nodo de la red es un supercomputador.
Adaptabilidad
SOTR distribuidos
necesidad de adaptación a cambios que se producen en el
entorno de operación del sistema de tiempo de ejecución.
Los tipos básicos de adaptación son la preventiva y la
reactiva. La adaptación preventiva trata de garantizar un
nivel de prestaciones y funcionalidad del software de
operación haciendo hipótesis sobre el comportamiento futuro
del sistema basándose en su comportamiento presente. La
adaptación reactiva se realiza en respuesta a eventos
inesperados.
Se trata de minimizar los tiempos de respuesta por parte de
la red: buses de campo, redes industriales, han de minimizar
el tiempo desde que se recoge algo en un sensor hasta que
llega a un actuador para ejecutar la orden que corresponda,
pasando por el gestor de la red. Otros problemas son
considerar que puede haber sobrecarga en la red y
problemas de sincronización de los relojes de los distintos
elementos del sistema distribuido.
183
Sistemas Operativos de Tiempo Real
Military; Aerospace
Automotive; Medical
Telecom; Datacom;
Office Products
Household Appliances;
Consumer Electronics
HARD RTOS
184
Hard Real-Time vs. Soft Real-Time
Commercial
Personal
Computers
SOFT RTOS
Hard Real Time
Wind River Systems
Integrated Development Environment
(format of embedded software)
Complex
• real time
• deterministic
• time critical
• failure can be catastrophic
Tornado, VxWorks
Integrated
Systems
pRISM+;
pRISM+;
MATRIXx
Microsoft
Lynx
QNX
3COM
Windows
CE
Palm Computing
Microware
OSOS-9 RTOS
Windows
98, NT, XP
Soft Real Time
Symbian
• less real time
• less deterministic
• not as time critical
• failure can be overcome
EPOC16 RTOS
Microtec
VRTX
JChorusOS
Sun Microsystems
JavaOS
SONY
Lucent
Nano OS, Aperios
Inferno
• Lynx
• TRON
• Microware
• Microtec
• Venturcom
In-house
RTOS
QNX Software
LynxOS
• Wind River
• Integrated Systems
• QNX
• Symbian
• Lucent
General Purpose OS
Commercial
• Microsoft (CE)
• Sun Microsystems (Java)
• Geoworks
Simple
Low
Footprint (Memory Size)
High
185
Source: Lehman Brothers
186
Source: Lehman Brothers
31
Planificación cíclica
Las tareas se van ejecutando de forma cíclica, de
acuerdo con una cola de tareas.
Estrategias de
planificación
Tarea A
completa
Tar. B
comp.
Tarea C
completa
···
Tarea N
complet
Tarea A
completa
···
Ventana de Tiempo
187
Planificación cíclica
188
Planificación por desalojo (preemptive)
Las ventajas son que se minimizan los cambios de contexto y que es
fácil diseñar un planificador para una tarea conociendo el caso peor. La
ventana de tiempo tiene que ser suficientemente pequeña para que su
constante de tiempo sea menor que la de la planta pero suficientemente
grande para contener las tareas a ejecutar. Las tareas se van ejecutando
siempre en el mismo orden. Cada ventana de tiempo se repite
indefinidamente, como por ejemplo, en los autómatas programables.
Entre los inconvenientes está el que es difícil la comunicación entre
tareas. No hay posibilidad de comunicación con eventos externos, por lo
que no es posible el tratamiento por interrupciones: la interrupción ha de
esperar a su ventana de tiempo. No hay desalojo, por lo que si una tarea
entra en un bucle infinito, no desocupará nunca la CPU. Otro
inconveniente es que si se cambian las especificaciones, hay que
modificar la ventana de tiempos.
Se trata de una estrategia no única, puede tener variantes. Las
tareas son desalojadas en el momento en que haya otra tarea con
mayor prioridad. Se produce por invocación de nuevas tareas, por
interrupción o por temporización. Cuando entra el planificador,
comprueba si la tarea que se está ejecutando tiene menos prioridad
que los que están en espera. En este caso, la desaloja. Por lo tanto,
una tarea puede ser desalojada antes de terminar su ejecución
• round-robin
Mecanismos de
planificación por
desalojo
• Con asignación de
prioridades
• estática
• dinámica
189
190
Planificación por desalojo (preemptive)
El planificador tiene que activarse cada cierto tiempo. Cuando se
activa, comprueba si la tarea actual debe seguir ejecutándose en
función de su prioridad. En cada intervalo de tiempo puede
activarse una nueva tarea con una prioridad mayor o menor que las
actuales. El tiempo del planificador es tiempo no útil para las tareas.
Sea cual sea la estrategia de planificación escogida, el sistema de
gestión de tareas ha de permitir el tratamiento de interrupciones.
Éstas pueden ser interrupciones hardware causadas por eventos
externos, o interrupciones software generadas por una tarea que se
está ejecutando. Una interrupción fuerza el cambio de contexto. El
proceso de tratamiento de interrupciones pasa a ejecución
desbancando a la tarea que se está ejecutando. Debido a esto, es
lógico pensar que en manipulador de interrupciones ha de ser
breve. Una vez que ha terminado se restaurará la tarea que fue
desalojada de la CPU o bien el planificador decidirá qué tarea pasa
a ejecución (esto depende de cómo se haya implementado el191
SOTR).
Estructuras de prioridad
192
32
Niveles de prioridad
Nivel de interrupción
En este nivel de prioridad se encuentran las rutinas de atención o de
servicio para las tareas o dispositivos que requieren una respuesta
muy rápida (en torno a milisegundos). Una de éstas tareas es el
planificador de tareas del Nivel de Reloj.
niveles de prioridad
NIVEL INTERRUPCIÓN
Generalmente las rutinas de atención tendrán una prioridad superior
al resto de las tareas puesto que lo que se pretende es que la
interrupción sea atendida rápidamente. Las interrupciones pueden
tener la misma o distinta prioridad (cada interrupción tendría un nivel
de prioridad diferente), dependiendo del sistema. En este último caso,
una interrupción puede desalojar a otra.
PRIORIDAD
prioridad del planificador del
Nivel de Reloj
niveles de prioridad
NIVEL DE RELOJ
prioridad del planificador del
Nivel Base
niveles de prioridad
La rutina de atención a la interrupción tiene que tener un código
optimizado de forma que consuma el mínimo tiempo posible de CPU,
ya que si una rutina de interrupción es llamada muchas veces, puede
introducir un retardo importante.
NIVEL BASE
193
Nivel de reloj
194
Nivel de reloj
Tareas que tiene alguna restricción temporal. Estas tareas se
pueden activar de forma periódica. Por ejemplo, muestreo de
señales, de control,… Encontraríamos tareas estrictas y no
estrictas. El planificador de tareas decide qué tarea debe ejecutarse
en función de las prioridades. Dentro de las tareas de reloj,
encontramos dos tipos:
Cíclicas. Son las tareas que precisan una sincronización de
elevada precisión con el mundo exterior. Su mayor requisito es que
su activación periódica se ejecute con precisión. De esta forma,
cada tarea cíclica tiene asociado un periodo exacto para su
activación. Se puede retardar la ejecución dentro de su periodo si
es bloqueada por otra más prioritaria. El planificador sólo considera
que cada tarea se tiene que ejecutar dentro de cada periodo.
cíclicas
de retardo.
activación
195
Nivel de reloj
196
Nivel de reloj
Ej. Tres tareas cíclicas A(20, 5), B(40, 5), C(80, 5):
Ej. Tres tareas cíclicas A(20, 1), B(40, 6), C(80, 25) con planificación
basada en prioridad sin desalojo:
Prioridad A > B > C :
Prioridad A > B > C :
20
C
B
20
A
C
Prioridad C > A > B :
B
C
A
B
A
197
198
33
Nivel de reloj
Nivel de reloj
Ej. Tres tareas cíclicas A(20, 1), B(40, 6), C(80, 25) con planificación
basada en prioridad con desalojo:
De retardo. La tarea tiene asociado un retardo desde que termina
hasta que comienza. El planificador tiene que disponer una lista de
tareas teniendo en cuenta cuando cada tarea debe activarse.
Cuando una tarea pasa de ready a delayed, entonces el watch-dog
del sistema sabe cuando debe despertarse. Puede ser o no
periódica ya que la activación se va a producir un intervalo después
de su finalización. De esta forma, desde una ejecución a la
siguiente se garantiza un tiempo durante el cual no se va a ejecutar
la tarea. Los instantes de activación no tiene porque estar
desplazados el mismo tiempo. Controlando este tiempo de retardo,
la tarea se puede convertir en periódica.
Prioridad A > B > C :
20
C
B
A
activación
199
200
Nivel base
No hay ninguna restricción temporal, sólo se requiere que se
ejecuten correctamente. Se activan bajo demanda en vez de a
intervalos de tiempo predeterminados.
Hay varias formas de planificar tareas de nivel base. Una de ellas
sería utilizar un algoritmo round-robin con rodajas de tiempo. Otros
planificadores: FIFO (First In, First Out), SJF (Shortest Job First)....
Gestión de tareas
La mayoría de los sistemas de tiempo real emplean estrategias de
prioridad incluso para las tareas de nivel base. La prioridad puede
ser fija (con el inconveniente de determinar las prioridades correctas
para una operación satisfactoria), o dinámica (que permitiría la
adaptación a circunstancias particulares). La asignación dinámica
de prioridades puede realizarse mediante un planificador de alto
nivel, o bien ad-hoc desde las propias tareas.
201
Gestión de tareas
202
Estados de las tareas
Hay tareas que pueden estar o no activas, con prioridades o no, que
tenemos que ejecutar con un esquema periódico o con retardo. El
módulo gestor de tareas es el encargado de realizar todo esto.
Sus funciones básicas son:
Conocer el estado de cada tarea
Planificar la asignación de tiempo de CPU a cada tarea
Iniciar
Existente
Preparada
Terminar
Crear
Activar
Desactivar
Realizar el cambio de contexto entre tareas
DESPACHADOR
(Dispatcher)
Suspendida
Destruir
No
existente
Suspender
Desactivar
203
Ejecutar
Suspender
PLANIFICADOR
(Scheduler)
En
ejecución
204
34
Estados de las tareas
Estados de las tareas
En ejecución (active, running): la tarea tiene el control de la CPU y
del resto de los recursos que necesite. Normalmente será la tarea
con mayor prioridad de las que están preparadas para ejecutarse.
Existente (existent, dormant, off): El sistema operativo es
consciente de la existencia de esta tarea pero aún no se le ha
asignado una prioridad y no se ha convertido en ejecutable.
Preparada (ready, runnable, on): Puede haber más de una tarea en
este estado. La tarea no ha de estar esperando por ningún recurso.
No existente (non-existent, terminated): El sistema operativo no es
consciente de la existencia de estas tareas, a pesar de que pueden
estar residiendo en la memoria del computador. Es decir, el código
está en memoria esperando a que se le asigne una zona de datos.
Suspendida (suspended, locked out, waiting, delayed): La
ejecución de las tareas que se encuentran en este estado ha sido
suspendida porque
la tarea ha solicitado algún recurso que no se encuentra disponible,
la tarea está esperando alguna señal de la planta (p.ej. una entrada de
un convertidor A/D),
la tarea está esperando el transcurso del tiempo. en general se puede
decir que están a la espera de un evento.
205
Descriptor de tareas
206
Planificador
Descriptor de tareas (TD), descriptor de procesos (PD), bloque
de control de tareas (TCB)...
El planificador (scheduler) se activa en los siguientes casos:
Identificación de la tarea (ID).
Interrupción del reloj de tiempo real y cualquier interrupción que
indique la finalización de una petición de E/S.
Prioridad de cada tarea(P).
Suspensión de una tarea debido a:
Estado de la tarea
retardo de tarea.
Zona de almacenamiento del entorno volátil.
finalización de tarea.
solicitud de una transferencia E/S.
Puntero a siguiente tarea en la lista de tareas
En ambos casos, el planificador busca la tarea más prioritaria
entre las que estén listas para ejecución.
207
208
35
Descargar