select函数:
select函数是最早出现的IO复用模型,形式为:select(int maxfd,fd_set * readfds,fd_set * writefds, fd_set * esceptfds, struct timeval* tvptr);
共有5个参数:
第一个参数是描述符的最大值加1,因为描述符是从0开始的,所以描述符的最大值加1表示告诉内核检查的描述符的最大个数;
第二个,第三个,第四个参数表示指向描述符集的指针,表示我们关心的可读,可写,以及出错的各个描述符;
第五个参数表示select愿意等待的时间的指针,可以分为三种情况:
如果该指针为NULL,表示永远等待;
如果tvptr->sec==0 &&tvptr->tv_usec==0则表示不等待直接返回;
如果tvptr->sec!=0 || tvptr->tv_usec != 0则表示等待指定的时间返回;
返回值:
同时select函数也有三个可能的返回值,他们分别为出错返回,超时返回,正常返回;
1)出错返回时,它不会修改送进去的描述符参数集合,返回值为-1,这一般会在例如所制定的描述符都没有准备好时捕获到一个信号的情况下出现;
2)超时返回时,会修改描述符的集合,将所有的集合都清0,且返回值为0,这一般是在所有的描述符都没有准备好而又超时的情况下出现;
3)正常返回,也会修改描述符的集合,返回值是准备好的描述符的个数;
所谓准备好是说:
对于读集合中的一个描述符进行read操作,不会阻塞,则该描述符是准备好的;
对于写集合中的一个描述符进行write操作,不会阻塞,则该描述符是准备好的;
若异常状态集中的一个描述符有一个未决异常状态,则该描述符是准备好的;
select函数的缺点:
1)FD_SETSIZE,最大为1024,表示关心的描述符个数最大为1024个;
2)会修改描述符集合,这就造成你需要每次都重新设定参数集合;
3)只返回准备好的描述符个数,并不指定那个准备好了
4)不是线程安全的;
注意:对于读写和异常状态,普通文件描述符总是返回准备好;即便一个文件已经读到末尾处,select也是认为这个描述符是可读的,需要在程序中判断是否已经读到文件末尾进行关闭文件,并且从相应的描述符集合中去除该文件描述符;
pselect函数:
另外还有一个select的变体pselect函数,这个函数比select函数多了两个功能:
1)更精准的超时时间,它可以精确到纳秒;
2)可以设定信号屏蔽字,如果为NULL,则与select一样,如果非空,则在调用该函数期间会自动以原子操作安装屏蔽字,在函数返回时,自动回复以前的信号屏蔽字;