在学习select函数时遇到一个问题,在循环中调用select函数,并设置了超时退出。循环第一次超时退出,第二次瞬间退出。使用select的部分代码如下:
int maxfd = -1;
fd_set read_fd;
struct timeval tv;//设置时间
tv.tv_sec = 1;
tv.tv_usec = 500000;
char buf[10] = {0};
while(1)
{
FD_ZERO(&read_fd);//清空集合
FD_SET(0,&read_fd);//将标准输入放入集合
switch(select(1,&read_fd,NULL,NULL,&tv))
{
case -1:
printf("select error\n");
break;
case 0:
printf("timeout\n");
break;
default:
if(FD_ISSET(0,&read_fd))
{
printf("reading!...");
read(0,buf,9);
printf("buf = %s\n",buf);
memset(buf,0,sizeof(buf));
}
break;
}
}
从逻辑上看,并没有什么问题,但在实际运行中,却只有第一次是超时退出的,后面就出现了timeout刷屏的情况。开始以为程序逻辑问题,进行一番修改最终还是没能解决。于是在网上查找了一番,最终定位了问题所在。用man手册查了一下select的描述,全是英文也没怎么看懂。百度翻译了一下,大致明白了意思。
DESCRIPTION
select() and pselect() allow a program to monitor multiple file descriptors, waiting until one or
more of the file descriptors become "ready" for some class of I/O operation (e.g., input possi‐
ble). A file descriptor is considered ready if it is possible to perform the corresponding I/O
operation (e.g., read(2)) without blocking.
select() and pselect() allow a program to monitor multiple file descriptors, waiting until one or
more of the file descriptors become "ready" for some class of I/O operation (e.g., input possi‐
ble). A file descriptor is considered ready if it is possible to perform the corresponding I/O
operation (e.g., read(2)) without blocking.
The operation of select() and pselect() is identical, with three differences:
(i) select() uses a timeout that is a struct timeval (with seconds and microseconds), while
pselect() uses a struct timespec (with seconds and nanoseconds).
pselect() uses a struct timespec (with seconds and nanoseconds).
(ii) select() may update the timeout argument to indicate how much time was left. pselect()
does not change this argument.
does not change this argument.
(iii) select() has no sigmask argument, and behaves as pselect() called with NULL sigmask.
第二条指出:(ii)select()可更新超时参数以指示剩下多少时间。pselect()不更改此参数。
大致意思就是说每次调用select,超时参数会改变,即timeout是上一次调用后剩余的时间。如果上一次是超时退出的,那么下一次时间就为0,这就导致上面说的第二次调用瞬间退出的造成timeout刷屏的现象。所以,在循环中需要这样修改一下:
while(1)
{
FD_ZERO(&read_fd);//清空集合
FD_SET(0,&read_fd);//将标准输入放入集合
//每调用一次select,timeout是上一次的剩余时间,即第二次都是为0,会导致频繁调用造成CPU高
//故在此每次需要重制timeout
tv.tv_sec = 1;
tv.tv_usec = 500000;
switch(select(1,&read_fd,NULL,NULL,&tv))
{
case -1:
printf("select error\n");
break;
case 0:
printf("timeout\n");
break;
default:
if(FD_ISSET(0,&read_fd))
{
printf("reading!...");
read(0,buf,9);
printf("buf = %s\n",buf);
memset(buf,0,sizeof(buf));
}
break;
}
}
每次循环重置超时时间,这样就不会出现select函数再次调用秒退的情况。