我们知道nginx中有libaio这项功能,为了研究AIO的一些常用接口用法,在网上找到一个例子,异步IO读取本地文件,亲自实践了一把,记录如下:
安装依赖库
在Ubuntu 16.04上需要事先安装
apt-cache search aio
sudo apt-get install libaio1 libaio-dev
如果是CentOS,需要执行下面的命令先查询再安装
yum search libaio
yum -y install libaio libaio-devel
//description: 测试Linux的原生AIO功能演示
//refer: http://blog.chinaunix.net/uid-16979052-id-3840266.html
//dependence:
// sudo apt-get install libaio1 libaio-dev (Ubuntu 16.04.1)
// yum -y install libaio libaio-devel (CentOS 6.x)
//compile: gcc -g epoll_aio.c -o epoll_aio -laio
//run: ./epoll_aio
//
#define _GNU_SOURCE
#define __STDC_FORMAT_MACROS
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <unistd.h>
#include <errno.h>
#include <libaio.h>
#include <sys/eventfd.h>
#include <sys/epoll.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <inttypes.h>
//为简单起见,需要事先从网上下载一个文件,并存放在当前目录下面,
//并设置它的大小,这里选择”http://news.sohu.com/“,存为aio_sample.html
#define TEST_FILE "aio_sample.html"
#define TEST_FILE_SIZE 239576
#define NUM_EVENTS 128
#define ALIGN_SIZE 512
#define RD_WR_SIZE 1024
struct custom_iocb {
struct iocb iocb;
int nth_request;
};
void
aio_callback(io_context_t ctx, struct iocb *iocb, long res, long res2)
{
struct custom_iocb *iocbp = (struct custom_iocb *) iocb;
printf
("nth_request: %d, request_type: %s, offset: %lld, length: %lu, res: %ld, res2: %ld\n",
iocbp->nth_request,
(iocb->aio_lio_opcode == IO_CMD_PREAD) ? "READ" : "WRITE",
iocb->u.c.offset, iocb->u.c.nbytes, res, res2);
}
int
main(int argc, char *argv[])
{
int efd, fd, epfd;
io_context_t ctx;
struct timespec tms;
struct io_event events[NUM_EVENTS];
struct custom_iocb iocbs[NUM_EVENTS];
struct iocb *iocbps[NUM_EVENTS];
struct custom_iocb *iocbp;
struct epoll_event epevent;
int i, j, r;
void *buf;
efd = eventfd(0, EFD_NONBLOCK | EFD_CLOEXEC);
if (efd == -1)
{
perror("eventfd");
return 2;
}
//打开本地测试文件
fd = open(TEST_FILE, O_RDWR | O_CREAT | O_DIRECT, 0644);
if (fd == -1)
{
perror("open");
return 3;
}
//截断到指定大小
ftruncate(fd, TEST_FILE_SIZE);
ctx = 0;
if (io_setup(8192, &ctx))
{
perror("io_setup");
return 4;
}
if (posix_memalign(&buf, ALIGN_SIZE, RD_WR_SIZE))
{
perror("posix_memalign");
return 5;
}
printf("buf: %p\n", buf);
for (i = 0, iocbp = iocbs; i < NUM_EVENTS; ++i, ++iocbp)
{
iocbps[i] = &iocbp->iocb;
io_prep_pread(&iocbp->iocb, fd, buf, RD_WR_SIZE, i * RD_WR_SIZE);
io_set_eventfd(&iocbp->iocb, efd);
io_set_callback(&iocbp->iocb, aio_callback);
iocbp->nth_request = i + 1;
}
if (io_submit(ctx, NUM_EVENTS, iocbps) != NUM_EVENTS)
{
perror("io_submit");
return 6;
}
epfd = epoll_create(1);
if (epfd == -1)
{
perror("epoll_create");
return 7;
}
epevent.events = EPOLLIN | EPOLLET;
epevent.data.ptr = NULL;
if (epoll_ctl(epfd, EPOLL_CTL_ADD, efd, &epevent))
{
perror("epoll_ctl");
return 8;
}
i = 0;
while (i < NUM_EVENTS)
{
uint64_t finished_aio;
if (epoll_wait(epfd, &epevent, 1, -1) != 1)
{
perror("epoll_wait");
return 9;
}
if (read(efd, &finished_aio, sizeof (finished_aio)) !=
sizeof (finished_aio))
{
perror("read");
return 10;
}
printf("finished io number: %" PRIu64 "\n", finished_aio);
while (finished_aio > 0)
{
tms.tv_sec = 0;
tms.tv_nsec = 0;
r = io_getevents(ctx, 1, NUM_EVENTS, events, &tms);
if (r > 0)
{
for (j = 0; j < r; ++j)
{
((io_callback_t) (events[j].data)) (ctx, events[j].obj,
events[j].res,
events[j].res2);
}
i += r;
finished_aio -= r;
}
}
}
close(epfd);
free(buf);
io_destroy(ctx);
close(fd);
close(efd);
remove(TEST_FILE);
return 0;
}
下面是演示结果
参考文献