I/O的多路转接: select

1. 概念:

     I/O多路转接技术, 是先构造一张有关描述符的列表, 然后调用一个函数, 直到这些描述符中的一个已准备好进行I/O时, 该函数才返回. 在返回时, 它告诉进程哪些描述符已经准备好可以进行I/O.

    在Linux下poll, pselect, select这三个函数都可以执行I/O多路转接操作, 今天我们主要说select函数.

 

2. select函数:

#include <sys/select.h>

int select(int maxfdp1, fd_set *restrict readfds, fd_set *restrict writefds, fd_set *restrict exceptfds,
               
struct timeval *restrict tvptr);

正常则返回准备就绪的描述符数, 超时则返回0, 出错则返回
-1.

下面对参数进行说明:

  • maxfdp1: MAX File Description Plus 1. 最大描述符+1.
  • tvptr: 等待时间, 用一个timeval结构的值表示, 有3种情况:
    • tvptr == NULL: 永远等待. 可被信号中断.
    • tvptr->tv_sec == 0 && tvptr->tv_usec == 0: 完全不等待, 测试所有指定的描述符并立即返回. 非阻塞轮询.
    • tvptr->tv_sec != 0 &7 tvptr->tv_usec != 0: 等待指定的时间数. 时间超过立即返回0. 可被信号中断.
  • readfds, writefds, exceptfds: 指向描述符集的指针, 分别是可读, 可写, 异常的描述符. 每个描述符集存放在一个fd_set数据类型中.

 

fd_set可进行以下3种处理:

  • 分配一个这种类型的变量.
  • 将这种类型的一个变量赋值给同类型的另一个变量.
  • 其他处理.

关于其他处理, 由以下几个宏来实现:

#include <sys/select.h>

/* 判断fd是否在描述符集fdset中 */
int FD_ISSET(int fd, fd_set *fdset);

在则返回非0, 不在则返回0.

 

#include <sys/select.h>

/* 将一指定位清楚 */
void FD_CLR(int fd, fd_set *fdset);

/* 设置fd_set变量的一个指定位为fd */
void FD_SET(int fd, fd_set *fdset);

/* 将fdset的所有位设置为0 */
void FD_ZERO(fd_set *fdset);

 

3. 说明:

    前面我们所说的"准备好", 具体地说是指:

  • 若对读集(readfds)中的一个描述符的read操作将不会阻塞, 则此描述符是准备好的.
  • 若对写集(writefds)中的一个描述符的write操作将不会阻塞, 则此描述符是准备好的.
  • 若异常状态集(exceptfds)中的一个描述符有一个未决异常状态, 则此描述符是准备好的. 现在, 异常状态包括:
    • 在网络连接上到达的带外数据.
    • 在处于数据包模式的伪终端上发生了某些状态.

    描述符的阻塞是否并不影响select的阻塞. 也就是说, 这是两种阻塞层关系, 比如: 读一个非阻塞描述符, 并且以超时值5s调用select, 则select最多阻塞5s. 又比如: 指定一个tvptr = NULL 来调用select, 则该描述符数据准备好或捕捉到一个信号之前, select是一直阻塞的.

 

4. pselect:

    POSIX.1 定义了一个select的变体, 即: pselect, 对于这个函数不多介绍, 只说一下和select的两点区别:

  • 超时结构, select用timeval, pselect用const timespec. 这使得时间更精确, 并且不会被修改.
  • pselect可使用一可选择的信号屏蔽字sigmask. 在调用pselect时, 以原子操作的方式安装该信号屏蔽字, 在返回时恢复以前的信号屏蔽字.

 

5. 实例:

    编写中, 等待添加...

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章