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: 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: 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 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: 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