The alarm()
call is for a one off signal.
To repeat an alarm, you have to call alarm()
again each time the signal occurs.
Another issue, also, is that you're likely to get EINTR
errors. Many system functions get interrupted when you receive a signal. This makes for much more complicated programming since many of the OS functions are affected.
In any event, the correct way to wait for the next SIGALRM
is to use the pause()
function. Something the others have not mentioned (instead they have tight loops, ugly!)
That being said, what you are trying to do would be much easier with a simple sleep()
call as in:
// print a message every second (simplified version)
for(;;)
{
printf("My Message\n");
sleep(1);
}
and such a loop could appear in a separate thread. Then you don't need a Unix signal to implement the feat.
Note: The sleep()
function is actually implemented using the same timer as the alarm()
and it is clearly mentioned that you should not mix both functions in the same code.
sleep(3)
may be implemented using SIGALRM
; mixing calls to alarm()
and sleep(3)
is a bad idea.
(From Linux man alarm
)
void alarm_handler(int)
{
alarm(1); // recurring alarm
}
int main(int argc, char *argv[])
{
signal(SIGALRM, alarm_handler);
alarm(1);
for(;;)
{
printf("My Message\n");
// ...do other work here if needed...
pause();
}
// not reached (use Ctrl-C to exit)
return 0;
}
You can create variations. For example, if you want the first message to happen after 1 second instead of immediately, move the pause()
before the printf()
.
The "other work" comment supposes that your other work does not take more than 1 second.
It is possible to get the alarm signal on a specific thread if work is required in parallel, however, this can be complicated if any other timers are required (i.e. you can't easily share the alarm()
timer with other functions.)
P.S. as mentioned by others, doing your printf()
inside the signal handler is not a good idea at all.
There is another version where the alarm()
is reset inside main()
and the first message appears after one second and the loop runs for 60 seconds (1 minute):
void alarm_handler(int)
{
}
int main(int argc, char *argv[])
{
signal(SIGALRM, alarm_handler);
for(int seconds(0); seconds < 60; ++seconds)
{
alarm(1);
// ...do other work here if needed...
pause();
printf("My Message\n");
}
// reached after 1 minute
return 0;
}
Note that with this method, the time when the message will be printed is going to be skewed. The time to print your message is added to the clock before you restart the alarm... so it is always going to be a little over 1 second between each call. The other loop is better in that respect but it still is skewed. For a perfect (much better) timer, the poll()
function is much better as you can specify when to wake up next. poll()
can be used just and only with a timer. My Snap library uses that capability (look for the run()
function, near the bottom of the file). In 2019. I moved that one .cpp file to the eventdispatcher library. The run()
function is in the communicator.cpp
file.