Linux提供了同步I/O多路复用(synchronous I/O multiplexing)方法select,该方法主要用户监测多个文件描述符是否准备好,也就是说该方法主要是监测I/O是否可操作,或者是出现了异常,不过它一次可以监视很多个文件描述符。select函数原型如下:
- int select(int nfds, fd_set *readfds, fd_set *writefds,
- fd_set *exceptfds, struct timeval *utimeout);
其中,readfds、writefds和exceptfds是三个待观察的文件描述符集合,在调用select函数前我们准备好待考察的文件描述符,根据需求分别放入相应集合中,如同参数名描述的那样,我们将等待可读的文件描述符放入readfds集合,将等待可写的放入writefds集合,将判断是否出现错误的描述符放入exceptfds集合。当select返回时,相应的集合中的文件描述符只剩下了符合期望的;当然这三个参数可以为nil。参数nfds指明传入select方法的文件描述符的总数,相同描述符同时放入多个集合只计数1。select方法是阻塞执行的,可以使用utimeout参数指定没有相应事件发生的时候,select方法最长执行多长时间。
Linux同时还提供了一个pselect函数,该函数定义如下:
- int pselect(int nfds, fd_set *readfds, fd_set *writefds,
- fd_set *exceptfds, const struct timespec *ntimeout,
- const sigset_t *sigmask);
从函数定义上来看,它与select方法有两处不同,第一是超时timeout不同,它们的数据类型不同,utimeout的数据类型是timeval,ntimeout的数据类型是timespec,它们的定义如下:
- struct timeval{
- time_t tv_sec; /* seconds */
- long tv_usec; /* microseconds */
- }
- struct timespec{
- long tv_sec; /* seconds */
- long tv_nsec; /* nanoseconds */
- }
也就是说select的超时只能达到毫秒级,而pselect可以达到纳秒级;同时在select中超时是通过指针传引用的,select方法会更新这个参数,指明还剩多长时间就会超时。