I/O复用使得程序能够同时监听多个文件描述符,对于提高程序性能至关重要。I/O复用不仅仅在网络程序中使用,但是我接触到的例子中,TCP网络编程那块使用I/O复用比较多,例如,TCP服务器同时处理监听socket和连接socket.
在了解I/O复用之前,我们需要先了解几个概念。
1,同步I/O与异步I/O
2,LT(水平触发)和ET(边缘触发)
POSIX把两个术语定义如下:
同步I/O:导致请求进程阻塞,直到I/O操作完成
异步I/O:不导致请求进程阻塞
阻塞是进程在等待某种资源,但是不能马上得到,必须等待别的进程释放资源才能继续,属于被动无法得到时间片,内核就切换其它进程运行。
它与休眠和挂起的区别:休眠一般为主动式的放弃一段CPU时间。
挂起是运行时间片到了,内核要调度其它进程运行,被动式的失去CPU。(挂起可以被别的进程给抢占导致挂起,也可以自己主动挂起自己。)
Unix下可用的5种I/O模型:1,阻塞式I/O 2,非阻塞式I/O 3,I/O 复用 4,信号驱动I/O(SIGIO) 5,异步I/O
1--4为同步I/O,5为异步I/O。
我们关注的I/O复用属于同步I/O,会导致进程阻塞。
在linux的IO多路复用中有水平触发,边缘触发两种模式,这两种模式的区别如下:
水平触发(LT,level-triggered,也被称为条件触发):只要满足条件,就触发一个事件(只要有数据没有被获取,内核就不断通知你).如果文件描述符已经就绪可以非阻塞的执行IO操作了,此时会触发通知.允许在任意时刻重复检测IO的状态,没有必要每次描述符就绪后尽可能多的执行IO.select,poll就属于水平触发.
边缘触发(ET,edge-triggered)每当状态变化时,触发一个事件.如果文件描述符自上次状态改变后有新的IO活动到来,此时会触发通知.在收到一个IO事件通知后要尽可能多的执行IO操作,因为如果在一次通知中没有执行完IO那么就需要等到下一次新的IO活动到来才能获取到就绪的描述符.信号驱动式IO就属于边缘触发.
epoll既可以选择水平触发,也可以选择边缘触发
下面具体介绍三大I/O复用:select,poll,epoll
int select(int nfds,fd_set *readfds,fd_set *writefds,fd_set *exceptfds,struct timeval *timeout);returns numbers of ready descriptors,0 on timeout,or -1 on errorint poll(struct pollfd fds[],nfds_t nfds,int timeout);returns number of ready file descriptors,0 on timeout,or -1 on error;epollint epoll_create(int size)int epoll_ctl(int epfd,int op,int fd,struct epoll_event * event)int epoll_wait(int epfd,struct epoll_event* events,int maxevents,int timeout);
评论列表()