Sistemas Informáticos de Tiempo Real
Temporización bajo UNIX:
Bucles de retardo:
La forma más sencilla y precisa de temporización
es ejecutar un bucle de espera sin hacer ningún trabajo útil,
por ejemplo:
while (i<N)
i++;
Esta forma de temporización tiene tres
problemas fundamentales:
-
consume tiempo de uso del procesador sin hacer trabajo
útil,
-
depende específicamente de la velocidad con
que cada procesador es capaz de ejecutar el bucle,
-
si el S.O. asigna el procesador a otro proceso temporalmente
se introducen pausas cuya longitud no podemos controlar ni predecir.
La única forma de garantizar la exactitud
de la temporización es seleccionar un planificador de tiempo real
durante la ejecución del bucle, bloqueando así la posibilidad
de que el S.O. asigne la CPU a otros programas. Aunque es una solución
poco aconsejable en un entorno multiproceso , los sistemas dedicados y
sistemas custom suelen usarla ya que es la única que permite realizar
temporizaciones exactas por debajo de los 10 ms.
Llamadas sleep, usleep, nanosleep:
Una forma más exacta de temporización
es usar los servicios de temporización del S.O. La forma más
simple es ejecutar una syscall de la familia sleep. Las llamadas
en cuestion son:
-
sleep (argumento en segundos)
-
usleep (argumento en microsegundos)
-
nanosleep (argumento en nanosegundos)
La forma de programar es sencilla:
while (1)
{
...hacer algo...
sleep(n);
...hacer otra cosa...
}
Los problemas de esta forma de temporización
son dos:
-
el tiempo que el S.O. tarda en despertar al proceso
depende del intervalo entre interrupciones de reloj, con lo que se introduce
un retardo adicional en cada pausa,
-
para lograr eventos periódicos tenemos que
controlar el tiempo que tardamos en procesar datos antes de volvernos a
dormir, ya que también forma parte del periodo entre eventos.
El fichero /home/soitrpr/unix/gettime.c
muestra un ejemplo de uso de SIGALRM.
Signals enviados por temporizadores (SIGALRM):
Los signals son equivalentes a interrupciones privadas
a cada proceso. En particular, los signales generados por temporizadores
envían un signal específico cuando transcurre un cierto intervalo
de tiempo. Para usarlos necesitamos:
-
programar previamente el signal con una rutina de
atención que se ejecuta cuando se recibe el signal,
-
usar una system call para programar el temporizador
y controlar la cuenta atrás.
La ventaja de este modelo de programación
es que el programa puede estar haciendo otra cosa distinta mientras espera
a que pase el tiempo. También existe una syscall (pause)
que permite no hacer nada hasta que llegue un signal para evitar consumir
tiempo de CPU cuando no tenemos nada que hacer excepto esperar. La desventaja
de este método es que también sufre las mismas imprecisiones
que la llamada sleep, debido a que la fuente de temporización
sigue siendo la interrupción de reloj del S.O.
void rutina_al ()
{
/* reprograma el temporizador
*/
alarm(10);
/* reprograma el signal */
signal(SIGALRM,rutina_al);
... hacer cosas...
}
...
signal(SIGALRM, rutina_al);
alarm(10);
while(1)
{
...hacer cosas...
/* esperar a que ocurra el signal */
pause();
}
El fichero /home/soitrpr/unix/padre.c
muestra un ejemplo de uso de SIGALRM.
Signals enviados por temporizadores POSIX (SIGALRM):
El interfaz de POSIX para temporización usa
en realidad los mismos recursos que el signal anterior, por lo que no pueden
usarse a la vez en el mismo programa ya que tanto el signal como el temporizador
son los mismos. La ventaja del interfaz POSIX es que es más cómodo
para definir timers periódicos que se vuelven a contar automáticamente
un nuevo intervalo de tiempo.
La llamada a usar es
void rutina_timer()
{
/* reprograma signal (no
el timer) */
signal(SIGALRM,rutina_timer);
}
...
struct itimerval val;
signal(SIGALRM,rutina_timer);
val.it_interval.tv_sec=segundos;
val.it_interval.tv_usec=microsegundos;
val.it_value.tv_sec=segundos;
val.it_value.tv_usec=microsegundos;
setitimer(ITIMER_REAL, &val, NULL);
while(1)
{
...hacer cosas...
/* esperar a que ocurra el signal */
pause();
}
El fichero /home/soitrpr/unix/timer_posix.c
muestra un ejemplo de uso de SIGALRM con setitimer para generar llamadas
periódicas a una subrutina.
© 1999 Guillermo Pérez Trabado
Departamento de Arquitectura de Computadores
Universidad de Málaga