背景: I/O模型介绍
非阻塞I/O
检查–检查–检查。。。。-----------发起---------完成
阻塞I/O
发起------------------(阻塞)-----------------------完成
I/O复用
检查-----(阻塞)----------------就绪 发起-------完成
阻塞于select,而非I/O操作
与阻塞I/O相比,操作多出一步,效率较低,其优势在于一次可以等待多个fd
信号驱动I/O
通知发起-------------------------------------------------完成
异步I/O
发起-------------------------------------------------------通知
附:I/O多路复用流程图
使用过程中阻塞了两次
select函数
用途
指示内核等待多个事件中的任意一个发生,并在其中一个事件发生时唤醒进程
多个I/O使用一个线程或少量线程等待
函数原型
int select(int max_fd, fd_set *read_fd, fd_set *write_fd, fd_set *except_fd, struct timeval *timeout);
//return_val: 0 for time out -1:err other: the num of ready fd
//int max_fd:最大的fd加一,表示循环等待的最大fd
//下面fd_set:存储关心的文件集
//struct timeval: null for 永久等待 值为0 for 不等待 其它值 for 等待的时间
//struct timeval {
// long tv_sec;//second
// long tv_usec;//microsecond
//};
文件集操作
FD_ZERO(fd_set *set);//清空文件集
FD_SET(int fd, fd_set *set);//添加一个文件
FD_CLR(int fd, fd_set *set);//删除一个文件
FD_ISSET(int fd, fd_set *set);//判断某一个是否存在
注意事项
系统调用可以被信号打断,select也不例外,因此在使用select时,应检查errno是否出现EINTR错误。
例程
/*================================================================
* Copyright (C) 2020 All rights reserved.
*
* Name :select.c
* Author :wzj
* Date :2020.04.13
* Decription:使用select等待/dev/tty(键盘)可读,
* 输入'q'退出当前进程
* 输入'\n'换行
*
================================================================*/
#include <stdio.h>
#include <stdlib.h>
#include <sys/select.h>
#include <sys/time.h>
#include <unistd.h>
#include <fcntl.h>
#include <errno.h>
int main()
{
int fd;
int max_fd;
fd_set read_fd;
struct timeval time_out;
int ret;
int read_num = 0;
unsigned char read_char = 0;
fd = open("/dev/tty", O_RDONLY | O_NONBLOCK, 0666);
if(fd < 0) {
printf("open file failed \n");
return -1;
}
while(1) {
FD_ZERO(&read_fd);
FD_SET(fd, &read_fd);
max_fd = fd + 1;
ret = select(max_fd, &read_fd, NULL, NULL, NULL);
if(ret < 0) {
if(errno == EINTR)
continue;
printf("select error\n");
return - 1;
}else if(ret == 0) {
printf("time out \n");
continue;
}
if(FD_ISSET(fd, &read_fd)) {
read_num = read(fd, &read_char, 1);
if(read_num <= 0) {
printf("read file failed\n");
return -3;
}
if(read_char == 'q') {
printf("quit process\n");
return 0;
}
if(read_char == '\n') {
printf("read new line\n");
continue;
}
printf("read %c\n", read_char);
}
}
}