Señales simples – Programación en C y función de alarma

4 minutos de lectura
#include  <stdio.h>
#include  <signal.h>


void  ALARMhandler(int sig)
{
  signal(SIGALRM, SIG_IGN);          /* ignore this signal       */
  printf("Hello");
  signal(SIGALRM, ALARMhandler);     /* reinstall the handler    */
}

int main(int argc, char *argv[])
{
  alarm(2);                     /* set alarm clock          */
  while (1)
    ;
  printf("All done");
}

Espero que el programa imprima “hola” después de 2 segundos, pero en su lugar, la salida es “zsh: alarm ./a.out”

¿Alguna idea de lo que está pasando?

Se está olvidando de configurar el controlador de alarma inicialmente. Cambiar el inicio de main() me gusta:

int main(int argc, char *argv[])
{
   signal(SIGALRM, ALARMhandler);
   ...

Además, el controlador de señales probablemente no imprimirá nada. Esto se debe a que la biblioteca C almacena en caché la salida hasta que ve el final de la línea. Entonces:

void  ALARMhandler(int sig)
{
  signal(SIGALRM, SIG_IGN);          /* ignore this signal       */
  printf("Hello\n");
  signal(SIGALRM, ALARMhandler);     /* reinstall the handler    */
}

Para un programa del mundo real, la impresión desde un controlador de señales no es muy segura. Un manejador de señales debe hacer lo menos posible, preferiblemente solo colocar una bandera aquí o allá. Y la bandera debe ser declarada volatile.

  • Ejemplo del mundo real: una vez trabajé en un sistema que usaba una base de datos de Access como back-end y, en determinadas circunstancias, un printf() llamar a un controlador de señal escribiría en el archivo .mdb en lugar de la salida estándar, lo que haría que la base de datos no tuviera reparación.

    – Juan Bode

    23 de noviembre de 2009 a las 20:22

avatar de usuario
McPherrinM

No está configurando el controlador en su main función.

antes de hacerlo alarm(2)Pon el signal(SIGALRM, ALARMhandler); en tus main.

Debería funcionar entonces.

Tenga en cuenta que su “Todo listo” nunca se imprimirá, porque permanecerá en el bucle while (1) después de que se haya ejecutado el procesador de señal. Si desea que el ciclo se rompa, deberá tener una bandera que cambie el controlador de señal.

#include <stdio.h>
#include <signal.h>
#include <unistd.h>

/* number of times the handle will run: */
volatile int breakflag = 3;

void handle(int sig) {
    printf("Hello\n");
    --breakflag;
    alarm(1);
}

int main() {
    signal(SIGALRM, handle);
    alarm(1);
    while(breakflag) { sleep(1); }
    printf("done\n");
    return 0;
}

  • +1 por el buen programa. Creo que tendrías que llamar alarm(2) en el manejador de señales: normalmente uno alarm() la llamada solo genera un solo SIGALRM

    – Andomar

    23 de noviembre de 2009 a las 16:24

  • Por supuesto, tienes razón. Obviamente no probé este código, y no he usado señales de esta manera por un tiempo (en particular, son inútiles en un entorno de subprocesos para usar de esta manera).

    – McPherrinM

    24 de noviembre de 2009 a las 5:29

  • ¿Cuál es la necesidad de dar una clase de almacenamiento volátil para la variable breakflag?

    – sujin

    11 de junio de 2013 a las 13:50

  • La intención de volatile era evitar que el compilador optimizara las tiendas o las cargas, por lo que las dos partes diferentes de la ejecución del código (bucle principal, controlador de señal) siempre ven correctamente los valores de la otra parte. Sin embargo, no confío en la exactitud de este código, y tal vez usaría un atómico en su lugar.

    – McPherrinM

    11 de junio de 2013 a las 19:14

  • Agregar #include <unistd.h> para deshacerse del mensaje de advertencia de la declaración implícita de la función ‘alarma’ y ‘dormir’

    – charles.cc.hsu

    25 de marzo de 2017 a las 3:42

No está instalando el controlador de señal primero.
Debe decirle al sistema que desea manejar la señal antes de recibirla, por lo que debe llamar signal() de la red principal antes de que llegue la señal.

int main(int argc, char *argv[])
{
  signal(SIGALRM, ALARMhandler);     /* install the handler    */
  alarm(2);                     /* set alarm clock          */
  while (1);
}

Andomar tiene razón. Pruebo esto y la versión 1 se imprime (cada segundo):

Hi...
Hi...
Hi...
Hi...
BYE
Hi...
...

impresiones de la versión 2 (cada cinco segundos):

Hi...Hi...Hi...Hi...BYE
Hi...Hi...Hi...Hi...BYE
...

Entonces el código es:

#include <stdio.h>
#include <unistd.h>
#include <signal.h>

# define T 5

int flag = T;

void sigalrm_handler(int);

int  main(void)
{
    signal(SIGALRM, sigalrm_handler);   
    alarm(1);                         
    while (1);  
}

void sigalrm_handler(int sig)
{
    if(--flag){
        printf("Hi...\n");   /*version 1*/
        /*printf("Hi...");*/ /*version 2*/
    }else{
        printf("BYE\n");
        flag=T;     
    }
    alarm(1);
}

¿Ha sido útil esta solución?

Esta web utiliza cookies propias y de terceros para su correcto funcionamiento y para fines analíticos y para mostrarte publicidad relacionada con sus preferencias en base a un perfil elaborado a partir de tus hábitos de navegación. Al hacer clic en el botón Aceptar, acepta el uso de estas tecnologías y el procesamiento de tus datos para estos propósitos. Configurar y más información
Privacidad