文章目录
- 一、IO多路复用
- (一)概念
- 1. 实现机制
- 2. 使用示例
- (二)IO多路复用实现原理
- (三)epoll函数
- 1. select/poll/epoll的区别
- 2. API
- 2. 使用示例
一、IO多路复用
(一)概念
在一个应用程序中如果需要同时监听多个文件描述符对应的数据时,就需要使用IO多路复用模型,IO多路复用有select/poll/epoll
方式。
将需要监听的文件描述符放到读表中,让后使用select统一监听,如果所有的文件描述符对应的数据都没有就绪进程休眠。如果有一个或者多个硬件数据就绪select对应的进程就会被唤醒,然后从就绪的读表中找出就绪的文件描述符,然后调用read函数将数据读取到用户空间即可。
1. 实现机制
US:fd_set rfds; //定义读取表fd1 = open("/dev/mycdev0",O_RDWR);fd2 = open("/dev/input/event1",O_RDWR);while(1){FD_ZERO(&rfds); //清空读表FD_SET(fd1,&rfds);//将fd1放到读表中FD_SET(fd2,&rfds); //将fd2放到读表中select(fd2+1,&rfds,NULL,NULL,NULL);if(FD_ISSET(fd1,&rfds)){ //fd1就绪read(fd1,buf1,sizeof(buf1));printf("buf1 = %s\n",buf1);}if(FD_ISSET(fd2,&rfds)){ //fd2就绪read(fd2,buf2,sizeof(buf2));printf("buf2 = %s\n",buf2);}}
---------------------------------------------------------
KS:file_operations:
//__poll_t (*poll) (struct file *, struct poll_table_struct *);
__poll_t mycdev_poll(struct file *file, struct poll_table_struct *wait)
{//1.调用poll_waitpoll_wait(file,等待队列头,wait);//2.判断数据是否就绪if(condition)return EPOLLIN; //EPOLLIN数据可读,EPOLLOUT数据可写return 0;
}
- 注:
- EPOLLIN —数据可读
- EPOLLOUT ----数据可写
2. 使用示例
mydev.c
- 注:select
(二)IO多路复用实现原理
current|
#define current get_current()
#define get_current() (current_thread_info()->task)|
struct thread_info {struct task_struct *task;}|
struct task_struct {pid_t pid;struct files_struct *files;
}|
//linux-5.10.61/include/linux/fdtable.h
struct files_struct {struct file __rcu * fd_array[NR_OPEN_DEFAULT];}|
struct file{
}
current在内核中指代当前进程
task_struct结构体里记录fd
进程与进程之间的fd互不影响
(三)epoll函数
1. select/poll/epoll的区别
- select(表)
select监听的最大文件描述符个数是1024
select会有清空表的过程,需要反复构造表,反复拷贝表,效率比较低
select对应的进程从休眠态被唤醒后,需要再次遍历文件描述符表,效率比较低 - poll(链表)
poll监听的文件描述符没有个数限制
poll没有清空表的过程,不需要反复构造表,反复拷贝表,效率比较高
poll对应的进程从休眠态被唤醒后,需要再次遍历文件描述符表,效率比较低 - epoll(红黑树(完全二叉树)+双向链表)------ 红黑树保存要监听的fd,双向链表保存就绪的fd
epoll监听的文件描述符没有个数限制
epoll没有清空表的过程,不需要反复构造表,反复拷贝表,效率比较高
epoll对应的进程从休眠态被唤醒后,不需要再次遍历文件描述符表,能直接拿到就绪的文件描述符,效率比较高
2. API
#include <sys/epoll.h>
int epoll_create(int size);
功能:参数:@size:无意义,但是必须填写大于0的值返回值:成功返回epfd;失败返回-1,重置错误码
//这个函数本质就是创建一个红黑树,用户通过epfd拿到红黑树,这个epfd也会占用一个fd值int epoll_ctl(int epfd, int op, int fd, struct epoll_event *event);
功能:参数:@epfd@op:操作方式EPOLL_CTL_ADD 添加EPOLL_CTL_MOD 修改EPOLL_CTL_DEL 删除@fd:被操作的文件描述符@event:事件类型返回值:成功返回0;失败返回-1,置位错误码int epoll_wait(int epfd, struct epoll_event *revents, int maxevents, int timeout);
功能:
参数:@epfd@revents@maxevents@timeout:超时时间=0 :立即返回>0 :=-1 :忽略超时,永久阻塞,直到有fd就绪
返回值:成功,返回就绪的文件描述符的个数;返回0,代表超时,没有文件描述符就绪失败,返回-1,重置错误码
2. 使用示例