事件轮询接口
epoll使得时间监听器的注册与实际的事件监视工作脱钩,有三种系统调用:
- 初始化epoll的上下文;
- 将要查看的文件描述符加入上下文(或移除);
- 实际执行时间等待。
#include <stdio.h>
#include <fcntl.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/uio.h>
#include <sys/epoll.h>
#include <memory.h>
#include <stdlib.h>
int main(){
//创建epoll,epfd为可用控制的句柄
int epfd = epoll_create(2);
struct epoll_event event1[2];
struct epoll_event event2[2];
event1[0].events = EPOLLIN;
event1[0].data.fd = STDIN_FILENO;
event1[1].events = EPOLLOUT;
event1[1].data.fd = STDOUT_FILENO;
int ret = epoll_ctl(epfd, EPOLL_CTL_ADD, STDIN_FILENO, &event1[0]);
ret = epoll_ctl(epfd, EPOLL_CTL_ADD, STDOUT_FILENO, &event1[1]);
struct epoll_event* events = (epoll_event*)malloc(sizeof(struct epoll_event)*2);
sleep(2);
int nr_events = epoll_wait(epfd, events, 2, -1);
int i;
for(i = 0; i < nr_events; i++){
printf("event=%d on fd=%d\n", events[i].events, events[i].data.fd);
}
free(events);
close(epfd);
return 0;
}
epoll最简单的程序就是这样吧。
关于ET、LT两种工作模式:
- ET模式仅当状态发生变化的时候才得到通知,这里的状态变化并不包括缓冲区还有未处理的数据,也就是即使没有把数据读完还有剩余的,下次wait的时候不会发现这个变化;
- LT模式下只要有数据就会一直通知下去。
用下面的程序可以看到这两种模式的区别:
int main(){
int epfd = epoll_create(2);
struct epoll_event event1[2];
event1[0].events = EPOLLIN|EPOLLET;//设置为边缘触发模式
event1[0].data.fd = STDIN_FILENO;
int ret = epoll_ctl(epfd, EPOLL_CTL_ADD, STDIN_FILENO, &event1[0]);
struct epoll_event* events = (epoll_event*)malloc(sizeof(struct epoll_event));
sleep(2);//输入ab
int nr_events = epoll_wait(epfd, events, 1, 10);
char ch;
read(STDIN_FILENO, &ch, 1);//注意这里和scanf的区别
printf("%d %c\n", nr_events, ch);
nr_events = epoll_wait(epfd, events, 1, 10);
read(STDIN_FILENO, &ch, 1);
printf("%d %c\n", nr_events, ch);
free(events);
close(epfd);
return 0;
}