select 系统调用允许程序同时在多个底层文件描述符上等待输入的到达、输出的完成,或产生错误信息。这意味着终端仿真程序可以一直阻塞到有事情可做为止。
select 函数对数据结构 fd_set 进行操作,它是由打开的文件描述符构成的集合。有一组定义好的宏可以用来控制这些集合:
#include <sys/types.h>
#include <sys/time.h>
void FD_ZERO(fd_set *fdset); //将 fd_set 初始化为空集合
void FD_SET (int fd, fd_set *fdset); //在 fd_set 中设置 fd
void FD_CLR (int fd, fd_set *fdset); //在 fd_set 中清除 fd
int FD_ISSET(int fd, fd_set *fdset); //判断 fd 是否是 fd_set 集合中的一个元素;若是,返回非零值。
当声明了一个文件描述符集后,必须用FD_ZERO将所有位置零:
fd_set demo;
FD_ZERO(&demo);
select 系统调用原型:
int select(int nfds, fd_set *readfds, fd_set *writefds, fd_set *errorfds, struct timeval *timeout);
参数 nfds 指定需要测试的文件描述符数目,测试的描述符范围从 0 到 nfds - 1 。
参数 timeout 用来防止无限期的阻塞,struct timeval 定义为:(time_t 在头文件 sys/types.h 中定义,整数类型)
struct timeval
{
time_t tv_sec; //seconds
long tv_usec; //microseconds
};
timeout 有三种情况:
(1)timeout == NULL 等待无限长的时间。等待可以被一个信号中断。当有一个描述符做好准备或者是捕获到一个信号时函数会返回。如果捕获到一个信号, select函数将返回 -1,并将变量 erro 设为 EINTR。
(2)timeout->tv_sec == 0 &&timeout->tv_usec == 0 不等待,直接返回。加入描述符集的描述符都会被测试,并且返回满足要求的描述符的个数。这种方法通过轮询,无阻塞地获得了多个文件描述符状态。
(3)timeout->tv_sec !=0 ||timeout->tv_usec!= 0 等待指定的时间。当有描述符符合条件或者超过超时时间的话,函数返回。在超时时间即将用完但又没有描述符符合条件的话,返回 0。对于第一种情况,等待也会被信号所中断。
函数返回:
(1)当监视的相应的文件描述符集中满足条件时,比如说读文件描述符集中有数据到来时,内核(I/O)根据状态修改文件描述符集,并返回一个大于0的数。返回值为状态发生变化的句柄个数。
(2)当没有满足条件的文件描述符,且设置的timeval监控时间超时时,select函数会返回一个为0的值。
(3)当select返回负值时,发生错误。
注:select可处理多个句柄状态同时发生变化的情况。