select() 函数学习

笔记分两部分,第一部分是Mannual中对select的重要段落的翻译,第二部分参考了博客,相关链接已在正文中给出。

Linux Programmer’s Manual

Description

select() 干了什么事情

select() 允许一个program监控多个 file descriptor,一直等到一个或者多个file descriptors对某类I/O操作变得ready(例如,input possible)
一个file descriptor被认为是ready的,如果它可以执行相应的I/O操作(如,read without blocking, or a sufficiently small write)
select() 只能监控file descriptors numbers小于FD_SETSIZE的那些file descriptors;poll没有这个限制
三个独立的sets of file descriptors被监控。列举在readfds中的file descriptors被监控,看characters变得available for reading(更精确的说,看是否read不会被block;特别的,一个file descriptor在end-of-file上也是ready的)。这个位于writefds中的file descriptor会被监控,看是否有space可以write(虽然,一个large write 也可能是block的)。位于exceptfds中的file descriptors会被监控,对那些exceptional conditions。(exceptional conditions的例子,可以查看在poll2中关于POLLPRI的讨论)

select() 退出的时候会有什么操作

select()退出的时候,每个file descriptor sets会在正确的位置被修改,以表明哪个file descriptor实际改变了状态。(于是,如果在一个loop中使用select()函数,这三类sets必须在每次select()被调用前重新初始化)
三类file descriptors sets中的任一file descriptor set都可以被指定为NULL,如果相应类别的事件没有file descriptors需要被监控的话。

对file descriptors sets进行操作所使用的macros

四个macros用于对sets进行操作。

  • FD_ZERO() 清空set
  • FD_SET() 给set add 一个file descriptor
  • FD_CLR() 给set remove 一个file descriptor
  • FD_ISSET() 测试一个file descriptor是否是某个set的元素,这个macro在select()返回之后有用。

nfds参数的描述

nfds应该被设置为highest-numbered file descriptor in any of the three sets,再加上1.
检查每个集合中指定的文件描述符,直到该限制为止。

Return value

成功的话,select()返回包含在三个returned descriptor sets的file descriptors的数量(就是,在readfds, writefds, exceptfds中被设置的bits的总数量),如果超时了的话,这个值可以是0。
失败的话:

  • -1将被返回
  • errno被设置来标识这个错误
  • file descriptor sets are unmodified
  • timeout becomes undefined

Other blogs

参考资源
select机制提供了一个数据结构 struct fd_set,这个结构可以理解为一个集合,实际上是一个位图,每一个特定的位来标识相应的file descriptor,fd_set集合可以通过一些macro来操纵,macro的具体信息已经在上文给出
深入理解fd_set,便于论述,取fd_set长度为1个字节,fd_set中的每一个bit可以对应一个file descriptor,因此1个字节的fd_set最大可以对应8个file descriptors

fd_set set;
FD_ZERO(&set);
// 此时,set的内容是00000000,左边是高位,右边是低位
FD_SET(fd, &set);
// 如果fd=5, 那么执行上述语句之后,set的内容是00100000
FD_SET(2, &set);
FD_SET(1, &set);
// set 的内容是00100110
select(6, &set, NULL, NULL, 0);
// 执行select,阻塞等待
// 如果fd=1,fd=2上都发生可读事件,则set内容变为00000110,没有发生可读事件的fd=5在set上的对应bit被清零

select() 函数的格式如下:

int select(int nfds, fd_set *readfds, fd_set *writefds,
                  fd_set *exceptfds, struct timeval *timeout);

上文中叙述过每个参数的含义,这里再详细说一下
nfds是一个整数值,其值为所有的file descriptors中的最大值加1,因为,Linux系统中的file descriptor是从0开始的,0号文件是stdin,即标准输入流
nfds的拼写中也能看出,number of file descriptors,即select()所monitor的file descriptors的数量。
对应到fd_set这个位图中,即是位图中有效bit的范围。

一个疑问

既然readfds,writefds,exceptfds都标识出了要监控的file descriptors都是谁,那为什么还要nfds这个参数呢?select() 是从0开始,一直监控到nfds-1吗?具体实现不清楚,但是,根据Linux Programmer’s Mannual中对Return Value的描述(见上文),select()只有在所监控的file descriptors变得ready之后、或者超时之后,才会return。这样看来,nfds参数的作用,可能是便于select()的实现吧!

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值