select
电平触发
#include<sys/time.h>
#include<sys/types.h>
#include<unistd.h>int select(int n, fd_set* readfds, fd_set* writefds, fd_set* exceptfds, struct timeval* timeout);
在指定的文件描述符准备好I/O之前或超过一定时间限制,select调用会被阻塞
readfds
文件描述符集合,监测可读数据
writefds
文件描述符集合,监测可写数据
exceptionfds
文件描述符集合,监测异常或带外out-of-band数据(适用于套接字)
成功返回时,每个集合只包含对应类型的I/O就绪的文件描述符
n
为所有集合中文件描述符的最大值加一
timeout
指向timeval
结构体
#include<sys/time.h>
struct timeval{long tv_sec; // secondslong tv_usec; // microseconds
}
若该参数不为NULL
,即使没有文件描述符处于I/O就绪态,select也会在指定时间后返回
若时限中两个都为0
,会立即返回,并报告调用时所有事件对应的文件描述符均不可用,且不等待任何后续操作
宏操作
通过宏来管理集合中的文件描述符,允许Unix系统按其希望的方式实现,大多数系统实现为位数组
FD_CLR(int fd, fd_set* set);
FD_ISSET(int fd, fd_set* set);
FD_SET(int fd, fd_set* set);
FD_ZERO(fd_set* set);
FD_ZERO
从集合中移除所有文件描述符
FD_SET
向集合中添加文件描述符
FD_CLR
从集合中移除文件描述符,设计良好的代码从不使用该函数
FD_ISSET
测试一个文件描述符是否在集合中,若不存在,返回0
由于文件描述符集合是静态建立的,所以文件描述符数量的上限和文件描述符的最大值均有限制
由FD_SETSIZE
设定,Linux上值为1024
返回值和错误码
成功时,返回所有集合中I/O就绪的文件描述符的数目,若指定了时限,返回值可能为0
错误时,返回-1
,同时errno
被设置为下列值
错误码 | 说明 |
---|---|
EBADF | 某一个集合中的一个文件描述符非法 |
EINTR | 等待时捕获了一个信号,可以重新发起调用 |
EINVAL | 参数n 为负数,或给出的时限不合法 |
ENOMEM | 没有足够的内存完成请求 |
示例
#include<stdio.h>
#include<sys/time.h>
#include<sys/types.h>
#include<unistd.h>#define TIMEOUT 5
#define BUF_LEN 1024int main(void){struct timeval tv;fd_set readfds;FD_ZERO(&readfds);FD_SET(STDIN_FILENO, &readfds);tv.tv_sec= TIMEOUT;tv.tv_usec= 0;int ret= select(STDIN_FILENO+1, &readfds, NULL, NULL);if(ret==-1){perror("select");return 1;}else if(!ret){printf("%d seconds elapsed.\n", TIMEOUT);return 0;}if(FD_ISSET(STDIN_FILENO, &readfds)){char buff[BUF_LEN+1];int len= read(STDIN_FILENO, buff, BUF_LEN);if(len==-1){perror("read");return 1;}if(len){buf[len]='\0';printf("read:%s\n", buf);}return 0;}fprintf(stderr, "this should not happen\n");return 0;
}
实现可移植的sleep
微秒级的睡眠机制
struct timeval tv;
tv.tv_sec = 0;
tv.tv_usec = 500;// sleep for 500 microseconds
select(0,NULL,NULL,NULL, &tv);
Linux提供了高精度的睡眠机制的实现