27
#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");
}

I expect the program to print "hello" after 2 seconds, but instead the output is "zsh: alarm ./a.out"

Any idea what is going on?

qwer
  • 325
  • 1
  • 3
  • 5

4 Answers4

35

You're forgetting to set the alarm handler initially. Change the start of main() like:

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

Also, the signal handler will probably print nothing. That's because the C library caches output until it sees an end of line. So:

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

For a real-world program, printing from a signal handler is not very safe. A signal handler should do as little as it can, preferably only setting a flag here or there. And the flag should be declared volatile.

Andomar
  • 232,371
  • 49
  • 380
  • 404
  • 25
    Real-world example: I once worked on a system that used an Access database as a back end, and under certain circumstances a `printf()` call in a signal handler would write to the .mdb file instead of stdout, hosing the database beyond repair. – John Bode Nov 23 '09 at 20:22
10

You're not setting the handler in your main function.

Before you do alarm(2), put the signal(SIGALRM, ALARMhandler); in your main.

It should work then.

Note that your "All Done" will never be printed, because you'll stay in the while(1) loop after the signal processor has run. If you want the loop to be broken, you'll need to have a flag that the signal handler changes.

#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;
}
Dylan
  • 23
  • 9
McPherrinM
  • 4,526
  • 1
  • 22
  • 25
  • 4
    +1 For the nice program. I think you'd have to call `alarm(2)` in the signal handler: normally one `alarm()` call only generates a single `SIGALRM` – Andomar Nov 23 '09 at 16:24
  • Of course, you're right. I obviously didn't test this code, and have't used signals in this manner in a while (Notably, they're useless in a threaded environment to use this way). – McPherrinM Nov 24 '09 at 05:29
  • what is the need of giving volatile storage class for breakflag variable? – sujin Jun 11 '13 at 13:50
  • 1
    The volatile was intended to prevent the compiler from optimizing out stores or loads, so the two different parts of code execution (main loop, signal handler) always correctly see the values from the other part. However, I am not confident in the correctness of this code, and I would perhaps use an atomic instead. – McPherrinM Jun 11 '13 at 19:14
  • Add `#include ` to get rid of the warning message of implicit declaration of function ‘alarm’ and 'sleep' – charles.cc.hsu Mar 25 '17 at 03:42
5

You are not installing the signal handler first.
You need to tell the system that you want to handle the signal before actually receiving it, so you need to call signal() from main before the signal comes.

int main(int argc, char *argv[])
{
  signal(SIGALRM, ALARMhandler);     /* install the handler    */
  alarm(2);                     /* set alarm clock          */
  while (1);
}
Arkaitz Jimenez
  • 22,500
  • 11
  • 75
  • 105
4

Andomar is rigth. I test this and, version 1 prints (every second):

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

version 2 prints (every five seconds):

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

So the code is:

#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);
}
alemol
  • 8,058
  • 2
  • 24
  • 29
  • Thanks for a complete and functioning code. I just pasted it into the top of my existing program's main{} and fired it up. – user2548100 Oct 01 '13 at 19:22