Use of timers in Linux -- alarm () & setitimer ():
1. Alarm
-------------------------------------------
Alarm () and signal () are enough if they are not required to be accurate.
Unsigned int alarm (unsigned int seconds)
Function Description: Alarm () is used to set the signal sigalrm to be transmitted to the current process after the number of seconds specified by the seconds parameter. If the seconds parameter is 0, the previously set alarm is canceled and the remaining time is returned.
Return Value: returns the remaining seconds of the previous alarm. If no alarm is set, 0 is returned.
After alarm () is executed, the process continues to be executed. In the later stage (after alarm), the process will receive the signal sigalrm and execute its processing function in seconds.
# Include <stdio. h>
# Include <unistd. h>
# Include <signal. h>
Void sigalrm_fn (INT sig)
{
Printf ("alarm! /N ");
Alarm (2 );
Return;
}
Int main (void)
{
Signal (sigalrm, sigalrm_fn );
Alarm (1);
While (1) pause ();
}
2. setitimer ()
-------------------------------------------
Int setitimer (INT which, const struct itimerval * value, struct itimerval * ovalue ));
Setitimer () is more powerful than alarm and supports three types of Timers:
Itimer_real: It is calculated based on the actual time of the system, and it sends the sigalrm signal.
Itimer_virtual:-Calculate the time spent by the process in the user State. It sends the sigvtalrm signal.
Itimer_prof: It is calculated based on the time spent by the process in the user and kernel states. It sends the sigprof signal.
Setitimer () the first parameter which specifies the timer type (one of the above three); the second parameter is an instance of the structure itimerval; the third parameter can not be processed.
If setitimer () is called successfully, 0 is returned; otherwise,-1 is returned.
The following is a simple example of setitimer calling. In this example, a sigalrm is sent every second and a sigvtalrm signal is sent every 0.5 seconds:
# Include <stdio. h>
# Include <stdlib. h>
# Include <unistd. h>
# Include <signal. h>
# Include <time. h>
# Include <sys/time. h>
Int sec;
Void sigroutine (INT signo ){
Switch (signo ){
Case sigalrm:
Printf ("catch a signal -- sigalrm/N ");
Signal (sigalrm, sigroutine );
Break;
Case sigvtalrm:
Printf ("catch a signal -- sigvtalrm/N ");
Signal (sigvtalrm, sigroutine );
Break;
}
Return;
}
Int main ()
{
Struct itimerval value, ovalue, value2; // (1)
SEC = 5;
Printf ("process ID is % d/N", getpid ());
Signal (sigalrm, sigroutine );
Signal (sigvtalrm, sigroutine );
Value. it_value. TV _sec = 1;
Value. it_value. TV _usec = 0;
Value. it_interval. TV _sec = 1;
Value. it_interval. TV _usec = 0;
Setitimer (itimer_real, & Value, & ovalue );// (2)
Value2.it _ value. TV _sec = 0;
Value2.it _ value. TV _usec = 500000;
Value2.it _ interval. TV _sec = 0;
Value2.it _ interval. TV _usec = 500000;
Setitimer (itimer_virtual, & value2, & ovalue );
For (;;)
;
}
(1)Struct itimerval
Struct itimerval {
StructTimevalIt_interval;/* timer interval */
Struct timeval it_value;/* Current Value */
};
ITimerVal: I --> Interval
Val --> Value
It_value in the itimerval structure is the time for reduction. When this value is 0, a corresponding signal is sent. Then, it_value is set to it_interval.
(2) setitimer ()
Setitimer () sets a timer for the process in which it is located, if itimerval.It_intervalIf the value is not 0 (neither of the it_interval fields is 0), the timer will remain valid (a signal will be sent every other time)
Note: The Linux signal mechanism is basically inherited from UNIX systems. In early Unix systems, the signal mechanism was relatively simple and original, and some problems were exposed in practice. Therefore, the signals built on the early mechanism were called "unreliable signals ", signals smaller than sigrtmin (sigrtmin = 32, sigrtmax = 63) are unreliable signals. This is the source of "unreliable signals. The main problem is that each time a process processes a signal, it sets the response to the signal as the default action. In some cases, it may lead to incorrect signal processing. Therefore, if you do not want such an operation, you need to call signal () again at the end of the signal processing function (), reinstall the signal.
***********************************
How to Implement precise timing and sleep in Linux within seconds
Sleep and alarm are provided in Linux, but they only provide sleep in seconds. In this case, some processes are obviously too long to sleep, so how can we make the process sleep at a lower time resolution? There are two methods I know. Here we will introduce them separately. The first method is to use a timer. The timer function provided by Linux is:
Int setitimer (INT which, const struct itimerval * value, struct itimerval * ovalue );
Which specifies the timer type. Linux provides three types of Timers: timer_real: accurate timer. When the timer times out, the sigalrm signal is sent. timer_virtual: Virtual timer, which only records the process time, changes according to the process execution time, accurate timing cannot be implemented, and the sigvtalrm signal is sent out upon timeout; timer_prof: Synopsis timer, which changes according to the process time and system time. It cannot implement accurate timing and issues the sigprof signal upon timeout; in the process, capture the signals sent by the timer, because after the process receives the signals sent by the timer timeout, the default action is to terminate. Value indicates the timer time. The related structure is as follows:
Struct itimerval {
Struct timeval it_interval;
Struct timeval it_value;
};
Struct timeval {
Long TV _sec;
Long TV _usec;
};
It_interval specifies the interval and it_value specifies the initial time. If only it_value is specified, the timer is implemented once. If it_interval is specified at the same time, the system reinitializes it_value to it_interval after the timeout, to implement repeated timer; if both are cleared, the timer is cleared. TV _sec provides second-level precision, while TV _usec provides microsecond-level precision. The first value is greater. Note that 1 S = 1000000 Ms. Ovalue is used to save the previous value, which is always null. If you use a timer provided by setitimer to sleep, you only need to block and wait for the timer signal. The second method is to use select to provide precise timing and sleep:
Int select (int n, fd_set * readfds, fd_set * writefds, fd_set * limit TFDs,
Struct timeval * timeout );
N refers to the range of monitored file descriptors. Generally, it is set to the FD + 1, readfds, writefds, and limit TFDs to be selected as read, write, and exception file descriptor sets, and timeout is the timeout time. The following macros may be used for file descriptor set operations:
Fd_clr (int fd, fd_set * Set); clear FD
Fd_isset (int fd, fd_set * Set); test whether FD is set
Fd_set (int fd, fd_set * Set); Sets FD
Fd_zero (fd_set * Set); clears the descriptor set
We cannot use these macros at this time, because we do not care about the state of the file descriptor, And we care about the select timeout. Therefore, we need to set readfds, writefds, and effectfds to null and only specify the timeout time. We don't care about N, so you can set it to any non-negative value. The implementation code is as follows:
Int mssleep (long MS ){
Struct timeval TV;
TV. TV _sec = 0;
TV. TV _usec = MS;
Return select (0, null, & TV );
}
Haha, how is it, isn't it easy? Conclusion: setitimer and select can both achieve precise sleep of processes. This article briefly introduces them and provides a simple implementation for select. I do not recommend setimer, because one Linux system provides limited timer (each process can have up to three different types of timer). In addition, it is not easy to implement ssetitimer.