Summary of several methods to implement timer Timer under Linux

  • 2020-05-12 06:39:03
  • OfStack

Timer Timer is widely used in scenarios. Under Linux, there are several methods as follows:

1. Use sleep() and usleep()

Where sleep precision is 1 second, usleep precision is 1 subtle, the specific code is not written. This method has obvious disadvantages. In the Linux system, sleep class functions cannot guarantee the accuracy, especially when the system is under heavy load, sleep1 will have timeout phenomenon.

2. Use semaphore SIGALRM + alarm()

The precision of this method can reach 1 second, in which the semaphore mechanism of *nix system is used. First, the semaphore SIGALRM processing function is registered, alarm() is called, and the timing length is set. The code is as follows:


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

void timer(int sig)
{
    if(SIGALRM == sig)
    {
        printf("timer\n");
        alarm(1);    //we contimue set the timer
    }

    return ;
}

int main()
{
    signal(SIGALRM, timer); //relate the signal and function

    alarm(1);    //trigger the timer

    getchar();

    return 0;
}

The alarm method is good, but it can't get below 1 second accuracy in the first place.

3. Use RTC mechanism

The RTC mechanism utilizes the Real Time Clock mechanism provided by the system hardware to read the RTC hardware /dev/rtc and set the RTC frequency through ioctl(). The code is as follows:


#include <stdio.h>
#include <linux/rtc.h>
#include <sys/ioctl.h>
#include <sys/time.h>
#include <sys/types.h>
#include <fcntl.h>
#include <unistd.h>
#include <errno.h>
#include <stdlib.h>

int main(int argc, char* argv[])
{
    unsigned long i = 0;
    unsigned long data = 0;
    int retval = 0;
    int fd = open ("/dev/rtc", O_RDONLY);

    if(fd < 0)
    {
        perror("open");
        exit(errno);
    }

    /*Set the freq as 4Hz*/
    if(ioctl(fd, RTC_IRQP_SET, 1) < 0)
    {
        perror("ioctl(RTC_IRQP_SET)");
        close(fd);
        exit(errno);
    }
    /* Enable periodic interrupts */
    if(ioctl(fd, RTC_PIE_ON, 0) < 0)
    {
        perror("ioctl(RTC_PIE_ON)");
        close(fd);
        exit(errno);
    }

    for(i = 0; i < 100; i++)
    {
        if(read(fd, &data, sizeof(unsigned long)) < 0)
        {
            perror("read");
            close(fd);
            exit(errno);

        }
        printf("timer\n");
    }
    /* Disable periodic interrupts */
    ioctl(fd, RTC_PIE_OFF, 0);
    close(fd);

    return 0;
}

This way is more convenient, using the system hardware provided by RTC, the accuracy is adjustable, and very high.

4. select()

This is the less popular method you see when you read APUE, and you use select() to set the timer; The principle USES the fifth parameter of the select() method, the first parameter is set as 0, and the three file descriptor sets are all set as NULL, and the fifth parameter is the time structure. The code is as follows:


#include <sys/time.h>
#include <sys/select.h>
#include <time.h>
#include <stdio.h>

/*seconds: the seconds; mseconds: the micro seconds*/
void setTimer(int seconds, int mseconds)
{
    struct timeval temp;

    temp.tv_sec = seconds;
    temp.tv_usec = mseconds;

    select(0, NULL, NULL, NULL, &temp);
    printf("timer\n");

    return ;
}

int main()
{
    int i;

    for(i = 0 ; i < 100; i++)
        setTimer(1, 0);

    return 0;
}

The precision of this method can reach the level of subtlety. There are many multithreaded timers based on select() on the Internet, which indicates that select() is still very stable.

Conclusion: if the system requirements are relatively low, you can consider using simple sleep(), after all, 1 line of code can solve; If the system requires high precision, RTC mechanism and select() mechanism can be considered.


Related articles: