Search code examples
ctimetimerposix

Counting time with timer in C


I want to run a C program in a specific duration. After this time the program should be terminated. I searched some documents about it but many of them use sleep function. I don't want to use it. I want to check the current time whether it is bigger than the target time in an infinite loop.

For example below code , my target time is 5 and when running time duration is bigger than the 5, the program should be terminated.

But the code causes an infinite loop. How can I solve this problem?

void thread_handler(union sigval sv) {
    char *s = sv.sival_ptr;
    /* Will print "5 seconds elapsed." */
    puts(s);
}

int main(void) {
    char info[] = "5 seconds elapsed.";
    timer_t timerid;
    struct sigevent sev;
    struct itimerspec trigger;
    struct itimerspec triggerAfter;

    memset(&sev, 0, sizeof(struct sigevent));
    memset(&trigger, 0, sizeof(struct itimerspec));

    sev.sigev_notify = SIGEV_THREAD;
    sev.sigev_notify_function = &thread_handler;
    sev.sigev_value.sival_ptr = &info;

    timer_create(CLOCK_REALTIME, &sev, &timerid);

    trigger.it_value.tv_sec = 5;

    timer_settime(timerid, 0, &trigger, NULL); 

    timer_gettime(timerid,&trigger);
    while (1) {
        if ((int)trigger.it_value.tv_sec > 5) { //checking the current time is bigger than the target time, it it is then exit from the program
            timer_delete(timerid);
            exit(0);
        }
    }
}

Solution

  • If you want to check and compare in a busy loop, you can simply call clock_gettime and completely avoid timers. The whole point of a timer is to avoid such busy loops.

    In your case your main thread can simply pause and you can exit from the thread_handler function, which is run on a dedicated thread by the timer handler.

    #include <time.h>
    #include <signal.h>
    #include <string.h>
    #include <stdlib.h>
    #include <stdio.h>
    #include <unistd.h>
    void thread_handler(union sigval sv) {
        char *s = sv.sival_ptr;
        /* Will print "5 seconds elapsed." */
        puts(s);
        exit(0);
    }
    
    int main(void) {
        char info[] = "5 seconds elapsed.";
        timer_t timerid;
        struct sigevent sev;
        struct itimerspec trigger;
        struct itimerspec triggerAfter;
    
        memset(&sev, 0, sizeof(struct sigevent));
        memset(&trigger, 0, sizeof(struct itimerspec));
    
        sev.sigev_notify = SIGEV_THREAD;
        sev.sigev_notify_function = &thread_handler;
        sev.sigev_value.sival_ptr = &info;
    
        if(0>timer_create(CLOCK_REALTIME, &sev, &timerid)) return perror("timer_create"),1;
    
        trigger.it_value.tv_sec = 5;
    
        if(0>timer_settime(timerid, 0, &trigger, NULL)) return perror("timer_settime"),1;
    
        pause();
    
    }
    

    If you still want to busy check, you need to have the timer_gettime in the waiting loop. Calling it just once won't make the trigger object auto-update on its own.