Setting timer and POSIX timer functions

Keywords: Linux Operation & Maintenance server

The most commonly used timer on Linux systems is the setitmer timer

settimmmer prototype:

int setitimer(int which, const struct itimerval *value, struct itimerval *ovalue);
which Is timer type, setitimer Three types of timers are supported:

ITIMER_REAL: Based on the real time of the system, it sends out SIGALRM Signal.
ITIMER_VIRTUAL: -Based on the time spent by the process in user mode, it sends SIGVTALRM Signal.
ITIMER_PROF: Based on the time spent by the process in user mode and kernel mode, it sends SIGPROF Signal.
setitimer()0 will be returned if the call is successful, otherwise it will be returned-1. 

The first parameter of setimer () which specifies the timer type (one of the three above); The second parameter is an instance of the itimerval structure; The third parameter cannot be processed.

The timer value is defined by the following structure:

struct itimerval {
    struct timeval it_interval; /* next value */
    struct timeval it_value;    /* current value */
};

struct timeval {
    time_t      tv_sec;         /* seconds */
    suseconds_t tv_usec;        /* microseconds */
};

it_interval specifies the interval, it_value specifies the initial timing time. If only it is specified_ Value is to realize a timing; If you also specify it_interval, the system will reinitialize it after the timeout_ Value is it_interval to realize repeated timing; If both are cleared, the timer is cleared.

tv_sec provides second accuracy, tv_usec provides microsecond accuracy, with the higher value first

Example code:

#include <stdio.h>
#include <sys/time.h>
#include <string.h>
#include <signal.h>
#include <time.h>


//Simple print information, timer trigger function
void print_info(int signo){
    printf("timer fired\n");
}

void init_sigaction(){
    struct sigaction act;
    act.sa_handler = print_info;
    act.sa_flags = 0;
    sigemptyset(&act.sa_mask);
    sigaction(SIGPROF,&act,NULL); //Set the processing function of signal SIGPROF to print_info

}


void init_time() {
    struct itimerval value;
    value.it_value.tv_sec=2; //After the timer is started, the corresponding function will be executed every 2 seconds
    value.it_value.tv_usec=0;
    value.it_interval=value.it_value;
    setitimer(ITIMER_PROF,&value,NULL); //Initialize timer and send SIGPROF signal when it expires
}

int main(int argc ,char *argv[]){

    init_sigaction();
    init_time();
    while(1);

    return 0;
}

Compile output:

This program uses PROF time. After two seconds of PROF time, it will print the timer fired string.

It should be pointed out that the accuracy of setimer timer is ms, i.e. 1 / 1000 second, which is enough to meet the needs of most applications. However, multimedia and other applications may require higher precision timing, so we need to consider using the next type of timer: POSIX Timer.

posix timer function

The most powerful timer interface comes from the POSIX clock series. The actions of creating, initializing and deleting a timer are divided into three different functions: timer_ Create(), timer_ Settime() (initialize timer) and timer_ Delete(). POSIX Timer enhances setimer and overcomes many problems of setimer:

  • 1. A process can only have one timer at a time. If the application needs to maintain multiple timers with different intervals at the same time, you must write your own code to maintain them. This is very inconvenient. With POSIX timers, a process can create as many timers as it wants.
  • 2. When the setitmer timer time arrives, it can only notify the process using timer by signal, while POSIX timer can have a variety of notification methods, such as signal or starting thread.
  • 3. When using setimer, the types of notification signals cannot be changed: SIGALARM, SIGPROF, etc., which are traditional signals rather than real-time signals, so there is a problem of timer overrun; POSIX Timer can use real-time signals.
  • 4. The accuracy of setimer is ms. POSIX Timer is designed for applications with real-time requirements. The interface supports ns level clock accuracy.

time_create [create a timer]

time_create function prototype:

 int timer_create(clockid_t clock_id, struct sigevent *evp, timer_t *timerid)

Parameter Description:

clock_id indicates which clock the timer is based on, * timerid loads the ID of the timer created. This function creates a timer and puts its ID in the position pointed to by timerid. The evp parameter specifies the asynchronous notification to be generated when the timer expires. clock_id values are as follows:

CLOCK_REALTIME :Systemwide realtime clock. //Time is the time saved by the system, that is, the time that can be displayed by the date command. This time can be reset.
CLOCK_MONOTONIC:Represents monotonic time. Cannot be set.
CLOCK_PROCESS_CPUTIME_ID :High resolution per-process timer.  //CLOCK_ PROCESS_ CPUTIME_ The meaning of ID is the same as itimer of setitimer_ Virtual is similar.
CLOCK_THREAD_CPUTIME_ID :Thread-specific timer.// CLOCK_ THREAD_ CPUTIME_ The ID takes the thread as the timing entity. A thread in the current process actually runs for a certain time before triggering the Timer.
CLOCK_REALTIME_HR :High resolution version of CLOCK_REALTIME.
CLOCK_MONOTONIC_HR :High resolution version of CLOCK_MONOTONIC.

If evp is NULL, a default signal will be generated when the timer expires_ For realtimer, the default signal is SIGALRM. To generate signals other than the default signal, the program must set evp - > sigev_ Signo is set to the desired signal code.

Member EVP - > sigev in struct sigevent structure_ Notify describes what action should be taken when the timer expires. Typically, the value of this member is SIGEV_SIGNAL, this value indicates that a signal will be generated when the timer expires. The program can set the member EVP - > sigev_ Notify is set to SIGEV_NONE to prevent a signal when the timer expires.

timer_settime [start a timer]

int timer_settime(timer_t timerid, int flags, const struct itimerspec *value, struct itimerspect *ovalue);

struct itimespec{
    struct timespec it_interval;
    struct timespec it_value;  
};
struct timespec{
    time_t tv_sec;
    long tv_nsec;  
};

Parameter Description:
If the value of flags is timer_ Absttime, the time value specified by value will be interpreted as an absolute value (the default interpretation of this value is relative to the current time). This modified behavior avoids obtaining the current time, calculating the relative difference between "this time" and "expected future time", and creating competitive conditions during the start of the timer. If the value of ovalue is not NULL, the previous timer expiration time will be stored in the itimerspec it provides. If the timer is not started before, all members of this structure will be set to 0.

//Gets the remaining time of an active timer
int timer_gettime(timer_t timerid,struct itimerspec *value);
	
//Gets the number of overruns of a timer
int timer_getoverrun(timer_t timerid);

It is possible that a timer has expired, and the signal generated when the same timer expired last time is still suspended. In this case, one of the signals may be lost. This is the timer overrun. The program can call timer_getoverrun to determine the number of times this overrun occurs on a specific timer. Timer overrun can only occur on the signal generated by the same timer. The signals generated by multiple timers, even those using the same clock and signal, will be queued without loss.

When the execution is successful, the timer_getoverrun() returns the number of additional timer expiration times between the initial expiration of the timer and the expiration of the notification process (for example, by signaling).

//Delete a timer
int timer_delete (timer_t timerid);

A successful timer_ The delete () call destroys the timer associated with the timerid and returns 0. When execution fails, this call will return - 1 and set errno to EINVAL. This unique error condition means that timerid is not a valid timer.

POSIX timer expiration notification method

SIGEV_NONE  No notification when timer expires...
SIGEV_SIGNAL    When the timer expires, it will send a signal to the process, sigev_signo Can be used to specify what signal to use.
SIGEV_THREAD    When the timer expires, a new thread will be started for the required processing
SIGEV_THREAD_ID(Only for Linux)  When the timer expires, a signal is sent to the specified thread.

Set notification method:

evp.sigev_value.sival_ptr = &timer;
evp.sigev_notify = SIGEV_THREAD;
evp.sigev_notify_function = handle;
evp.sigev_value.sival_int = 3;   //As an argument to handle()
ret = timer_create(CLOCK_REALTIME, &evp, &timer);

Here, the notification method is set to SIGEV_THREAD, handle is the entry function. Then set the Timer interval and start the Timer:

ts.it_interval.tv_sec = 1;
ts.it_interval.tv_nsec = 0;
ts.it_value.tv_sec = 3;
ts.it_value.tv_nsec = 0;
ret = timer_settime(timer, TIMER_ABSTIME, &ts, NULL);

Sample code

#include <stdio.h>
#include <sys/time.h>
#include <string.h>
#include <signal.h>
#include <time.h>


void  handle(union sigval v){
    time_t t;
    char p[32];
    time(&t);
    strftime(p, sizeof(p), "%T", localtime(&t));
    printf("%s thread %lu, val = %d, signal captured.\n", p, pthread_self(), v.sival_int);
    return;
}

int main(int argc, char *argv[]){

    struct sigevent evp;
    struct itimerspec ts;
    timer_t timer;
    int ret;
    memset   (&evp, 0, sizeof(evp));
    evp.sigev_value.sival_ptr = &timer;
    evp.sigev_notify = SIGEV_THREAD;
    evp.sigev_notify_function = handle;
    evp.sigev_value.sival_int = 3;   //As an argument to handle()
    ret = timer_create(CLOCK_REALTIME, &evp, &timer);
    if( ret){
        perror("timer_create");
    }
   
    ts.it_interval.tv_sec = 1;
    ts.it_interval.tv_nsec = 0;
    ts.it_value.tv_sec = 3;
    ts.it_value.tv_nsec = 0;
    ret = timer_settime(timer, TIMER_ABSTIME, &ts, NULL);
    if( ret )
    {
        perror("timer_settime");
    }

    while(1);

}

Compile output:

Posted by jpmm76 on Wed, 27 Oct 2021 21:57:45 -0700