IO多路复用之poll
前面我们看到了select有很多的缺点,这里我们再来认识一下poll:
函数原型:
这里第一个参数中的fds实际上是一个struct pollfd的数组,数组中的每个元素代表一个文件描述符,下面是poolfd结构体的原型,其中第一个成员表示所要关注的文件描述符,第二个成员表示要关注的就绪事件,第三个成员代表返回的就绪事件。
第二个参数表示这个数组的长度,即要关注的文件描述符的个数
第三个参数表示超时时间,单位是毫秒。负数表示无限等待,0表示不等待直接返回,正数表示要等待的最小时间。
我们使用poll完成对标准输入读状态就绪的等待:
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <poll.h>
#include <stdlib.h>
int main()
{
struct pollfd fds;
fds.fd=0;
fds.events=POLLIN;
while(1)
{
int ret=poll(&fds,1,-1);
if(ret<0)
{
perror("poll");
return 1;
}
char buf[1024]={0};
ssize_t read_size=read(0,buf,sizeof(buf)-1);
if(read_size<0)
{
perror("read");
return 1;
}
if(read_size==0)
{
printf("read done\n");
return 0;
}
buf[read_size]='\0';
printf("%s\n",buf);
}
return 0;
}
输入输出进行分离
poll的优点:
- 使用pollfd这样的结构体来表示一个文件描述符的状态,其中使用events和revents将输入和输出进行分离,比起select中输入输出都体现在一个参数上,输出每次会覆盖输入,poll解决了这一问题。
- 解决了select中文件描述符数量被限制的问题
poll的缺点:
- 每次调用poll时,还是得重新传所有的文件描述符
- 每次调用poll,也要从用户态拷贝到内核态,并且拷贝的数据相比select远远增多,select中每个文件描述符只拷贝一位,而poll要拷一个结构体,文件描述符很多时,开销非常大,效率更低。
- 与select一样,不论是从用户拷到内核还是从内核拷到用户,都要进行遍历。