=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=