=Start=
缘由:
学习需要
正文:
参考解答:
首先看看select函数原型如下:
int select(int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, struct timeval *timeout);
参数说明:
slect的第一个参数nfds为fdset集合中最大描述符值加1,fdset是一个位数组,其大小限制为__FD_SETSIZE(1024),位数组的每一位代表其对应的描述符是否需要被检查。
select的第二三四个参数表示需要关注读、写、错误事件的文件描述符位数组,这些参数既是输入参数也是输出参数,可能会被内核修改用于标示哪些描述符上发生了关注的事件。所以每次调用select前都需重新初始化fdset。
timeout参数为超时时间,该结构会被内核修改,其值为超时剩余的时间。
#include <stdio.h>
#include <stdlib.h>
#include <sys/time.h>
#include <sys/types.h>
#include <unistd.h>
int main(int argc, char const *argv[])
{
fd_set rfds;
/* Watch stdin (fd 0) to see when it has input. */
FD_ZERO(&rfds);
FD_SET(0, &rfds);
struct timeval tv;
/* Wait up to five seconds. */
tv.tv_sec = 5;
tv.tv_usec = 0;
int retval;
retval = select(1, &rfds, NULL, NULL, &tv);
/* Don't rely on the value of tv now! */
if (retval == -1)
perror("select()");
else if (retval)
printf("Data is available now.\n");
/* FD_ISSET(0, &rfds) will be true. */
else
printf("No data within five seconds.\n");
printf("Hi, this is just a printf to test if select() will block code below select() or not.\n"); // result: block
return EXIT_SUCCESS;
}
利用select实现定时器,需要利用其timeout参数,注意到:
1)select函数使用了一个结构体timeval作为其参数。
2)select函数会更新timeval的值,timeval保持的值为剩余时间。
如果我们指定了参数timeval的值,而将其他参数都置为0或者NULL,那么在时间耗尽后,select函数便返回,基于这一点,我们可以利用select实现精确定时。
timeval的结构如下:
struct timeval {
long tv_sec; /* seconds */
long tv_usec; /* microseconds */
}
我们可以看出其可以精确到 microseconds 也即微秒。下面是实际代码:
#include <stdio.h>
#include <sys/time.h> /* struct timeval */
#include <time.h> /* time() */
#include <errno.h>
#include <inttypes.h>
#include <math.h>
void print_current_time_with_ms(void)
{
long ms; // Milliseconds
time_t s; // Seconds
struct timespec spec;
clock_gettime(CLOCK_REALTIME, &spec);
s = spec.tv_sec;
ms = round(spec.tv_nsec / 1.0e6); // Convert nanoseconds to milliseconds
printf("Current time: %"PRIdMAX".%03ld seconds since the Epoch\n", (intmax_t)s, ms);
}
void print_current_timestamp(void)
{
time_t ltime; /* calendar time */
ltime = time(NULL); /* get current cal time */
// printf("%s", asctime(localtime(<ime)));
printf("%s", ctime(<ime));
}
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);
}
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);
}
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);
}
int main(int argc, char const *argv[])
{
int i;
for(i=0; i<5; ++i) {
// printf("[%d]\t%lu\n", i, (unsigned long)time(NULL));
// print_current_time_with_ms();
print_current_timestamp();
// seconds_sleep(1);
// milliseconds_sleep(1500);
microseconds_sleep(1900000);
}
return 0;
}
参考链接:
Linux C的select函数的使用
linux c中select使用技巧
linux c/c++网络编程之—select模型
linux c学习笔记—-select函数详解
linux下使用select实现精确定时器
Linux下获取当前时间(毫秒精度) # clock_gettime()
=END=