Tema Ejemplo Ps
Tema Ejemplo Ps
Tema Ejemplo Ps
Interrupciones. Sincronización y
comunicación entre tareas. Lenguajes.
Índice
1. Introducción. .............................................................................................. 2
2. Sistemas de tiempo real. Características. Lenguajes............................. 2
2.1. STR y programación orientada a eventos. ........................................ 3
2.2. Lenguajes y herramientas para desarrollo de STR ........................... 4
3. Sistemas basados en interrupciones....................................................... 5
3.1. Enmascaramiento de interrupciones. ................................................ 6
3.2. Anidamiento de interrupciones. ......................................................... 7
4. Programación concurrente. Procesos e hilos. ........................................ 8
4.1. Procesos vs hilos............................................................................... 8
4.2. Definición de procesos. ..................................................................... 9
4.3. Definición de hilos. .......................................................................... 10
4.4. Mecanismos de sincronización y coordinación. ............................... 11
4.4.1. Exclusión mutua. ......................................................................... 12
4.4.2. Uso de semáforos. ...................................................................... 14
4.4.3. Uso de datos atómicos. ............................................................... 14
5. Programación asíncrona. ........................................................................ 15
5.1. Los callbacks. .................................................................................. 15
5.2. Promesas y futuros.......................................................................... 16
6. Sistemas de tiempo real cliente-servidor. ............................................. 17
6.1. Comunicación tradicional cliente-servidor. ...................................... 18
6.2. Comunicación en tiempo real cliente-servidor. ................................ 18
7. Conclusión. .............................................................................................. 20
8. Bibliografía. .............................................................................................. 21
Academia Uni10 – http://www.uni10.es Tema 28
1. Introducción.
Los paradigmas de programación han ido evolucionando a lo largo del tiempo
para satisfacer las necesidades de los usuarios relativas a simular procesos en
tiempo real. Para afrontar este nuevo paradigma, normalmente se parte de los
conocimientos previos de programación secuencial en paradigmas
estructurados u orientados a objetos.
Este tema forma parte del bloque del temario referido a la programación, que
abarca desde el tema 23 hasta el tema 33. En concreto, forma un bloque sobre
los diferentes paradigmas de programación, el cual lo componen los temas 25
(programación estructurada), tema 26 (programación modular), tema 27
(programación orientada a objetos) y tema 28 (programación en tiempo real).
No obstante, también se relaciona directa o indirectamente con el resto de
temas del bloque, e incluso con algunos temas de otros bloques, como el tema
16, dedicado a la gestión de procesos en el sistema operativo.
En función de lo crítico o no que sea el factor tiempo, los STR pueden ser:
Cuando uno o más dispositivos genera una señal de interrupción, la CPU debe
identificar por software el dispositivo causante de la interrupción, y en caso de
ser varios, establecer el orden de prioridad entre ellos. La identificación se
realiza consultando los registros de estado locales de cada módulo de E/S.
Para describir con más detalle la forma en que opera la combinación de las
prioridades y el anidamiento en un sistema de interrupciones, consideremos
una CPU con tres líneas de interrupción: INT0, INT1, INT2, siendo la primera la
más prioritaria, y la última la menos prioritaria. Supongamos que llegan tres
peticiones de interrupción en el orden temporal del siguiente esquema: primero
se produce la interrupción INT1, luego INT2 y finalmente INT0.
antes de que finalice, llegan INT2 (que se pospone) e INT0 (que se añade a la
pila por delante de INT1). Cuando INT0 finaliza, se sigue atendiendo INT1, y
cuando ésta finaliza, se trata finalmente la interrupción INT2.
Por otra parte, tanto hilos como procesos también tienen una serie de
características comunes. Por ejemplo, ambos tienen una serie de estados por
los que pasan durante su ciclo de vida:
#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
void ejemploFork()
{
int x = 1;
if (fork() == 0)
printf("El hijo tiene x = %d\n", ++x);
else
printf("El padre tiene x = %d\n", --x);
}
int main()
{
ejemploFork();
return 0;
}
La salida del programa mostrará los mensajes “El padre tiene x = 0” y “El hijo
tiene x = 2”, en un orden arbitrario (dependiendo de quién finalice o acceda
antes a la CPU). Pero, en cualquiera de los dos casos, queda evidenciado que
ambos procesos tienen un contexto propio, y una copia propia de la variable x.
Como hemos comentado, los hilos son una especie de procesos “ligeros”, que
comparten un contexto común (variables locales compartidas). Normalmente
los hilos se crean a partir de un programa, y dependen de éste (cuando el
programa finaliza, lo hacen los hilos que ha generado).
t1.start();
t2.start();
}
}
La clase Thread es la que se encarga de definir los hilos (a partir de los objetos
Runnable creados antes), y el método start los pone en ejecución. A partir de
ese punto, se alternarán para ocupar la CPU (en el caso de sistemas con un
solo núcleo) hasta finalizar la tarea.
En este ejemplo, la hebra o hilo que actualiza el saldo debe bloquear al resto
antes de la lectura del saldo y desbloquearlo una vez actualizado su valor. Ésta
es la manera de garantizar que el resultado de la actualización será el mismo
que se hubiera producido si solamente tuviéramos un hilo en ejecución.
class GestionCuentaBancaria
{
int saldo;
Esta sección crítica puede ser accedida por distintos hilos para hacer distintas
operaciones:
// Variable compartida
GestionCuentaBancaria cuenta = new GestionCuentaBancaria();
Runnable r1 = () -> {
cuenta.actualizarSaldo(100);
};
Runnable r2 = () -> {
cuenta.actualizarSaldo(-50);
};
Así, por ejemplo, el lenguaje Java ofrece distintos tipos de datos atómicos,
como por ejemplo AtomicInteger o AtomicLong, que sirven para tipos
numéricos. También ofrece el tipo AtomicReference, que se emplea para
convertir en atómico cualquier tipo de dato compuesto que se quiera, e incluso
AtomicReferenceArray, para definir un array de objetos del tipo que se quiera,
como atómico. El siguiente código, por ejemplo, define una variable de texto
(String) de forma atómica.
Así, cualquier modificación que se haga sobre ella se ejecutará de una sola
vez, evitando que la cadena se pueda corromper por el acceso simultáneo de
varios hilos. Si, por ejemplo, hay varios hilos intentando cambiar el valor, o
añadiendo texto uno a continuación de otro, se garantiza que el resultado final
sería el mismo que si los hilos se ejecutasen de forma secuencial.
5. Programación asíncrona.
La programación asíncrona es una técnica que permite lanzar tareas en
paralelo a la tarea principal, igual que ocurre con la programación concurrente.
Pero, a diferencia de ésta, en la programación asíncrona estas tareas no
compiten por ningún recurso compartido, por lo que no es necesario ningún
mecanismo de sincronización entre ellas.
Un callback es una función que se le pasa como parámetro a otra para que la
ejecute cuando finalice. Es el mecanismo que proporcionan algunos lenguajes,
como JavaScript, para hacer llamadas asíncronas a otras funciones, y no
esperar a recoger el resultado.
Cuando se utiliza una promesa, se deben tener en cuenta las dos posibles
opciones: que se finalice correctamente o que se haya producido un error. En
JavaScript, por ejemplo, esto se controla a través de las cláusulas then y catch,
de forma que se ejecutará la primera si todo ha ido bien, o la segunda si ha
fallado algo.
Libros.findById('5ab2dfb06cf5de1d626d5c09')
.then(resultado => {
console.log('Resultado encontrado:', resultado);
})
.catch(error => {
console.log('ERROR:', error);
});
paso. Por otro lado, permite agrupar varias de estas llamadas síncronas en una
función asíncrona, para que el resultado completo del proceso no haga esperar
al programa principal, o a quien llame a la función. Es un mecanismo más
elegante y abreviado de enlazar llamadas asíncronas que deben esperarse
consecutivamente para seguir. Por ejemplo: buscar un libro por su id, asociarle
un autor y guardar los cambios.
CompletableFuture<Integer> cf =
CompletableFuture.supplyAsync(
() -> {
try
{
TimeUnit.SECONDS.sleep(3);
return (new Random()).nextInt(100);
} catch (InterruptedException ex) {
return -1;
}
});
En cualquier caso, cualquier aplicación web que podamos encontrar nos sirve
de ejemplo para ilustrar este tipo de comunicaciones, utilizando muy diversas
tecnologías, entre los lenguajes y frameworks que hemos comentado
anteriormente:
Para ello, podemos emplear algunos mecanismos de bajo nivel, como el uso de
sockets en distintos lenguajes de programación (Java, C#, C++…). El socket
establece un canal de comunicación entre los dos extremos, de forma que
cualquiera de las dos partes puede enviar información a la otra.
otra parte (siempre que esta otra parte esté preparada para recibirlos). En el
caso de Java, por ejemplo, esto se puede conseguir a través de sockets UDP.
// Enviar mensaje
String texto = "Hola";
byte[] mensaje = texto.getBytes();
DatagramPacket enviado =
// Mensaje a enviar, tamaño, dirección destino y
puerto
new DatagramPacket(mensaje, mensaje.length,
InetAddress.getLocalHost(), 2000);
socket.send(enviado);
// Recibir mensaje
byte[] buffer = new byte[1024];
DatagramPacket recibido =
new DatagramPacket(buffer, buffer.length);
socket.receive(recibido);
7. Conclusión.
Como hemos visto, un sistema en tiempo real (STR) es un sistema informático
en el que, para que las operaciones que se realizan sean correctas, no sólo es
necesario que la lógica e implementación de los programas sean correctas,
sino también el tiempo en el que dichas operaciones entregan su resultado. Si
las restricciones de tiempo no son respetadas.
Como hemos podido ver a lo largo del tema, existen multitud de lenguajes y
herramientas que podemos utilizar para desarrollar sistemas de tiempo real.
Desde algunas más tradicionales como C o C++, hasta otras más actuales
como JavaScript o Java, pasando por distintos frameworks y librerías de apoyo
para la construcción de estas aplicaciones, tales como socket.io, Laravel,
Symfony, Angular, etc.
8. Bibliografía.