Linux五种IO模型和fctnl的使用
input / output :访问外设
recv:大部分时间是在等,一部分时间是在真正做IO : IO = 等 + 拷贝
由于IO大部分时间是在等待的,那么要高效IO,单位时间去减少等的时间。
如何提高IO的效率——减少单位时间等的比重
5种IO模型
例子:钓鱼
钓鱼=等+ 钓
河:OS 鱼 :数据 钓:数据就绪条件 鱼竿:文件描述符
1.张三:只看着鱼漂,谁叫都不理。 阻塞式IO 80%+等待 同步IO
2.李四:一会看鱼漂,一会玩手机 非阻塞式轮询IO VS阻塞式IO :等的方式不同 同步IO
3.王五:铃铛绑在鱼竿上,当铃铛响了,自己知道应该去收杆了 信号驱动式IO(SIGIO)王五钓鱼的时候需要自己做 同步IO
4.赵六:放置200个鱼竿,一遍一遍遍历200个鱼竿 钓鱼效率最高 多路复用 同步IO
5.田七:发起了钓鱼,但自己干别的事去了。让小王去钓鱼 异步IO
同步IO:只要参与IO的过程(等或拷贝)就是同步IO
阻塞IO
非阻塞IO
底层数据没准备好,不会阻塞住,而是返回一个值告诉进程数据没准备好,此时进程可以做其他事情。
信号驱动IO
多路转接 IO高效
操作系统提供了一个特定的系统调用select,select一次可以等待多个文件描述符,它处理的是IO中等的过程
一旦数据准备好了,recvfrom就可以立即参与拷贝,从内核拷贝到用户。
异步IO
非阻塞IO-fcntl
实现非阻塞
先获取该文件描述符的文件状态标记
再去设置文件状态设置为非阻塞模式 O_NONBLOCK
tips:系统IO函数通常要对,sizeof(buffer)-1,而c语言的IO函数不用减一,因为它自身会对字符串做处理
如果以非阻塞方式读,不会被read阻塞住,返回值以出错的值-1返回,
我们是需要将read错误和read非阻塞的情况靠errno区分开的
便于我们对这两种情况做不同的处理
if(errno==EAGAIN || errno == EWOULDBLCOK)
{
//TO DO other work
}
else
{
cerr<< "read errno"<<errno<< strerrno(errno)<<endl;
}
被信号中断 IO中断
标准的写法中 还要写入
else if(errno==EINTR) // 这种也不是read出错了
未设置非阻塞:光标一直等待我们输入,代码阻塞在read函数上。
设置非阻塞,可以看到运行中并没阻塞在read函数上,而是一直在做其他事
代码
#include <iostream>
#include <unistd.h>
#include <fcntl.h>
#include <errno.h>
#include <string.h>
using namespace std;
void SetNoBlock(int fd)
{
int fl=fcntl(fd,F_GETFL);
if (fl<0)
{
cerr<<"fcntl error"<<errno<<strerror(errno)<<endl;
return;
}
fcntl(fd,F_SETFL,O_NONBLOCK|fl);
}
int main()
{
char buffer[1024];
SetNoBlock(0);
while (true)
{
int n =read(0,buffer,sizeof(buffer)-1);
if(n>0)
{
buffer[n]=0;
cout<<"read info: "<<buffer<<endl;
}
else if(n==0)
{
cout<<"read finish"<<endl;
break;
}
else
{
if(errno==EAGAIN || errno== EWOULDBLOCK)
{
//非阻塞
cout<<"do other thing"<<endl;
sleep(1);
continue;
}
else if(errno = EINTR)
{
//信号中断
break;
}
else
{
//出错
cerr<<"read error"<<errno<<strerror(errno)<<endl;
break;
}
}
}
}