Linux中select函数在循环中使用注意事项

在学习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.
       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).
       (ii)   select()  may  update  the timeout argument to indicate how much time was left.  pselect()
              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函数再次调用秒退的情况。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值