1.为什么会有异步I/O
aio异步读写是在linux内核2.6之后才正式纳入其标准。之所以会增加此模块,是因为众所周知我们计算机CPU的执行速度远大于I/O读写的执行速度,如果我们用传统的阻塞式或非阻塞式来操作I/O的话,那么我们在同一个程序中(不用多线程或多进程)就不能同时操作俩个以上的文件I/O,每次只能对一个文件进行I/O操作,很明显这样效率很低下(因为CPU速度远大于I/O操作的速度,所以当执行I/O时,CPU其实还可以做更多的事)。因此就诞生了相对高效的异步I/O
2.异步I/O的基本概念
所谓异步I/O即我们在调用I/O操作时(读或写)我们的程序不会阻塞在当前位置,而是在继续往下执行。例如当我们调用异步读API aio_read()时,程序执行此代码之后会接着运行此函数下面的代码,并且与此同时程序也在进行刚才所要读的文件的读取工作,但是具体什么时候读完是不确定的
3.异步aio的基本API
API函数 | 说明 |
---|---|
aio_read | 异步读操作 |
aio_write | 异步写操作 |
aio_error | 检查异步请求的状态 |
aio_return | 获得异步请求完成时的返回值 |
aio_suspend | 挂起调用进程,直到一个或多个异步请求已完成 |
aio_cancel | 取消异步请求 |
lio_list | 发起一系列异步I/O请求 |
上述的每个API都要用aiocb结构体赖进行操作
aiocb的结构中常用的成员有
struct aiocb
{
//要异步操作的文件描述符
int aio_fildes;
//用于lio操作时选择操作何种异步I/O类型
int aio_lio_opcode;
//异步读或写的缓冲区的缓冲区
volatile void *aio_buf;
//异步读或写的字节数
size_t aio_nbytes;
//异步通知的结构体
struct sigevent aio_sigevent;
}
4异步I/O操作的具体使用
(1)异步读aio_read
aio_read函数请求对一个文件进行读操作,所请求文件对应的文件描述符可以是文件,套接字,甚至管道其原型如下
int aio_read(struct aiocb *paiocb);
该函数请求对文件进行异步读操作,若请求失败返回-1,成功则返回0,并将该请求进行排队,然后就开始对文件的异步读操作
需要注意的是,我们得先对aiocb结构体进行必要的初始化
具体实例如下
aio_read
#include<stdio.h>
#include<sys/socket.h>
#include<netinet/in.h>
#include<arpa/inet.h>
#include<assert.h>
#include<unistd.h>
#include<stdlib.h>
#include<errno.h>
#include<string.h>
#include<sys/types.h>
#include<fcntl.h>
#include<aio.h>
#define BUFFER_SIZE 1024
int MAX_LIST = 2;
int main(int argc,char **argv)
{
//aio操作所需结构体
struct aiocb rd;
int fd,ret,couter;
fd = open("test.txt",O_RDONLY);
if(fd < 0)
{
perror("test.txt");
}
//将rd结构体清空
bzero(&rd,sizeof(rd));
//为rd.aio_buf分配空间
rd.aio_buf = malloc(BUFFER_SIZE + 1);
//填充rd结构体
rd.aio_fildes = fd;
rd.aio_nbytes = BUFFER_SIZE;
rd.aio_offset = 0;
//进行异步读操作
ret = aio_read(&rd);
if(ret < 0)
{
perror("aio_read");
exit(1);
}
couter = 0;
// 循环等待异步读操作结束