linux文件IO:select
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; // seconds
long 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 1024
int 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提供了高精度的睡眠机制的实现

浙公网安备 33010602011771号