关于select函数中struct timeval问题

来源:互联网 发布:兰溪行知学院最新消息 编辑:程序博客网 时间:2024/04/28 19:12
如果select调用中设置了等待时间,那么每次调用时都需要重新对这个时间赋值么?就像对fd_set处理一样。 
例如: 
fd_set readfd; 
struct timval tv; 
while(1) { 
  FD_ZERO(&readfd); 
  FD_SET(fd, &readfd); 
  tv.tv_sec = 2; 
  tv.tv_usec = 0; 
  select(maxfd+1, &readfd, NULL, NULL, &tv); 
  ......; 


如上代码,对fd_set需要每次调用都要重新设置,那么对tv来说是否也是一样呢?能不能把对tv的赋值放在while外面?
-------------------------------
之外意思就变了。
------------------------------
传的是一个引用进去,select里面可能会改变这个地址里保存的内容。所以每次循环都必须重新赋值
------------------------------
如楼主将时间的初始化放在外边,时间初始化为2秒,假设在1秒后发上了事件,则select将会返回并将tv的时间变成上次阻塞的剩余时间,即1秒,然后再进行监视套接字。这是因为linux系统对select()的实现中会修改参数tv为剩余时间。所以在循环内部使用函数select的时候一定要在循环内部初始化时间参数。
 
==================================================================
所以对于select函数中的最后一个参数,需要在循环中设置,每次循环要重新设置。如果设在循环外面,当循环执行起来后,每次循环select都会修改tv的值,tv的值越来越小,导致最后会产生select函数这tv时间内收不到有效时间,而返回-1,造成错误。
==================================================================
在网络程序中,一个进程同时处理多个文件描述符是很常见的情况。select()系统调用可以使进程检测同时等待的多个I/O设备,当没有设备准备好时,select()阻塞,其中任一设备准备好时,select()就返回。
    这个函数真是神通广大,用来定时也不错。select(0, NULL, NULL, NULL, &tv)tv每次执行select前都要重新设定一遍,不然就变成0了。感觉它的精度比usleep()要高一些。

select()的调用形式为:
    #include <sys/select.h>
    #include <sys/time.h>
    int select(int maxfd, fd_set *readfds, fd_set *writefds, fe_set *exceptfds, const struct timeval *timeout);

    select的第一个参数是文件描述符集中要被检测的比特数,这个值必须至少比待检测的最大文件描述符大1;参数readfds指定了被读监控的文件描述符集;参数writefds指定了被写监控的文件描述符集;而参数exceptfds指定了被例外条件监控的文件描述符集。
    参数timeout起了定时器的作用:到了指定的时间,无论是否有设备准备好,都返回调用。timeval的结构定义如下:
    struct timeval{
        long tv_sec; //秒
        long tv_usec; //微秒
    }
    timeout取不同的值,该调用就表现不同的性质:
    timeout为0,调用立即返回;
    timeout为NULL,select()调用就阻塞,直到知道有文件描述符就绪;
    timeout为正整数,就是一般的定时器。
    select调用返回时,除了那些已经就绪的描述符外,select将清除readfds、writefds和exceptfds中的所有没有就绪的描述符。select的返回值有如下情况:
    正常情况下返回就绪的文件描述符个数;
    经过了timeout时长后仍无设备准备好,返回值为0;
    如果select被某个信号中断,它将返回-1并设置errno为EINTR。
    如果出错,返回-1并设置相应的errno。
原创粉丝点击