When writing programs, we often use timers. First look at the Select function prototype as follows:
Copy Code code as follows:
int select (int Nfds, fd_set *readfds, Fd_set *writefds,
Fd_set *exceptfds, struct timeval *timeout);
Parameter description:
The first parameter of Slect Nfds is the maximum descriptor value in the Fdset collection plus 1,fdset is a bit array with a size limit of __fd_setsize (1024), and each bit of the bit array represents whether the corresponding descriptor needs to be checked.
The No. 234 parameter of the select represents an array of file descriptor bits that require attention to read, write, and error events, both as input parameters and as output parameters, and may be modified by the kernel to indicate which descriptors are concerned with events. Therefore, the fdset must be reinitialized each time a select is invoked.
The timeout parameter is a timeout, and the structure is modified by the kernel, and the value is the time remaining for the timeout period.
Using Select to implement the timer, you need to take advantage of its timeout parameters and note:
1 The Select function uses a structural body timeval as its parameter.
2 The Select function updates the Timeval value, and the Timeval holds the remaining time.
If we specify the value of the parameter Timeval, and the other parameters are set to 0 or null, then the SELECT function returns after the time is exhausted, based on which we can use Select to achieve precise timing.
The structure of the Timeval is as follows:
Copy Code code as follows:
struct timeval{
Long tv_sec;/*secons*
Long tv_usec;/*microseconds*/
}
We can see that its precision to microseconds is also subtle.
First, second level timer
Copy Code code as follows:
void Seconds_sleep (unsigned seconds) {
struct Timeval TV;
Tv.tv_sec=seconds;
tv.tv_usec=0;
int err;
do{
Err=select (0,NULL,NULL,NULL,&TV);
}while (err<0 && errno==eintr);
}
Second, millisecond level timer
Copy Code code as follows:
void Milliseconds_sleep (unsigned long mSec) {
struct Timeval TV;
tv.tv_sec=msec/1000;
Tv.tv_usec= (msec%1000) *1000;
int err;
do{
Err=select (0,NULL,NULL,NULL,&TV);
}while (err<0 && errno==eintr);
}
Third, subtle level timer
Copy Code code as follows:
void Microseconds_sleep (unsigned long uSec) {
struct Timeval TV;
tv.tv_sec=usec/1000000;
tv.tv_usec=usec%1000000;
int err;
do{
Err=select (0,NULL,NULL,NULL,&TV);
}while (err<0 && errno==eintr);
}
Now let's write a few lines of code to see the timing effect.
Copy Code code as follows:
#include <stdio.h>
#include <sys/time.h>
#include <errno.h>
int main ()
{
int i;
for (I=0;i<5;++i) {
printf ("%d\n", I);
Seconds_sleep (1);
Milliseconds_sleep (1500);
Microseconds_sleep (1900000);
}
}
Note: Although a delicate level of resolution is specified in the TIMEVAL structure, the kernel support is often not that high, and many UNIX cores round the timeout value up to multiples of 10ms. In addition, with the kernel scheduling delay phenomenon, that is, the timer time, the kernel also need to spend a certain amount of time to schedule the operation of the corresponding process. As a result, the precision of the timer is ultimately determined by the difference rate supported by the kernel.
Category: Linux