文章插图
异步阻塞IO模型的流程图
在Direct IO模式下,异步是非常有必要的(因为绕过了pagecache,直接和磁盘交互) 。linux Native AIO正是基于这种场景设计的,具体的介绍见:KernelAsynchronousI/O (AIO)SupportforLinux 。下面我们就来分析一下AIO编程的相关知识 。
阻塞模式下的IO过程如下:
int fd = open(const char *pathname, int flags, mode_t mode);ssize_t pread(int fd, void *buf, size_t count, off_t offset);ssize_t pwrite(int fd, const void *buf, size_t count, off_t offset);int close(int fd);
因为整个过程会等待read/write的返回,所以不需要任何额外的数据结构 。但异步IO的思想是:应用程序不能阻塞在昂贵的系统调用上让CPU睡大觉,而是将IO操作抽象成一个个的任务单元提交给内核,内核完成IO任务后将结果放在应用程序可以取到的地方 。这样在底层做I/O的这段时间内,CPU可以去干其他的计算任务 。但异步的IO任务批量的提交和完成,必须有自身可描述的结构,最重要的两个就是iocb和io_event 。libaio中的structs
struct iocb { void *data; /* Return in the io completion event */ unsigned key; /*r use in identifying io requests */ short aio_lio_opcode; short aio_reqprio; int aio_fildes; union { struct io_iocb_common c; struct io_iocb_vector v; struct io_iocb_poll poll; struct io_iocb_sockaddr saddr; } u;};struct io_iocb_common { void *buf; unsigned long nbytes; long long offset; unsigned flags; unsigned resfd;};
iocb是提交IO任务时用到的,可以完整地描述一个IO请求:data是留给用来自定义的指针:可以设置为IO完成后的callback函数;
aio_lio_opcode表示操作的类型:IO_CMD_PWRITE | IO_CMD_PREAD;
aio_fildes是要操作的文件:fd;
io_iocb_common中的buf, nbytes, offset分别记录的IO请求的mem buffer,大小和偏移 。
struct io_event { void *data; struct iocb *obj; unsigned long res; unsigned long res2;};
io_event是用来描述返回结果的:obj就是之前提交IO任务时的iocb;
res和res2来表示IO任务完成的状态 。
libaio提供的API和完成IO的过程libaio提供的API有:io_setup, io_submit, io_getevents, io_destroy 。
1. 建立IO任务
int io_setup (int maxevents, io_context_t *ctxp);
io_context_t对应内核中一个结构,为异步IO请求提供上下文环境 。注意在setup前必须将io_context_t初始化为0 。当然,这里也需要open需要操作的文件,注意设置O_DIRECT标志 。
2.提交IO任务
long io_submit (aio_context_t ctx_id, long nr, struct iocb **iocbpp);
提交任务之前必须先填充iocb结构体,libaio提供的包装函数说明了需要完成的工作:void io_prep_pread(struct iocb *iocb, int fd, void *buf, size_t count, long long offset){ memset(iocb, 0, sizeof(*iocb)); iocb->aio_fildes = fd; iocb->aio_lio_opcode = IO_CMD_PREAD; iocb->aio_reqprio = 0; iocb->u.c.buf = buf; iocb->u.c.nbytes = count; iocb->u.c.offset = offset;}void io_prep_pwrite(struct iocb *iocb, int fd, void *buf, size_t count, long long offset){ memset(iocb, 0, sizeof(*iocb)); iocb->aio_fildes = fd; iocb->aio_lio_opcode = IO_CMD_PWRITE; iocb->aio_reqprio = 0; iocb->u.c.buf = buf; iocb->u.c.nbytes = count; iocb->u.c.offset = offset;}
推荐阅读
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- Linux和Windows两种风格的操作系统,创建线程的方式有何不同?
- 计算机编程必备技巧——使用递归
- Linux Scsi子系统框架介绍
- Java8——异步编程
- 新手怎么才能学好UG/CNC编程呢?首先得先了解三大加工流程
- linux之间传文件命令之Rsync傻瓜式教程
- 微软提交补丁,用Linux替代Hyper-V根分区的Win
- 借助 HTTP 通过 SSH 绕过 Linux 防火墙
- Linux或者Mac下命令行speedtest测试网络速度
- 在浏览器中异步下载文件监听下载进度