AIO in C

AIO, 即异步非阻塞I/O,允许了包括I/O与处理计算的重叠。在大量并发任务下,理论上可以提高相应的处理计算性能。在此简单记录一下C语言中的AIO,方便后续有需要时候查询。

在Unix中,所有的I/O本质上都是对文件描述符的一种操作。在AIO中对应的文件描述符为一个叫aiocb(AIO I/O Control Block)的结构体。这个结构体存储了关于当下传输的所有信息,包括一个用户端的数据缓存。当I/O完成或者产生异常时,aiocb可以用来唯一的标识这一个已经停止的I/O操作。aiocb的结构如下:

1
2
3
4
5
6
7
8
9
10
11
struct aiocb {

int aio_fildes; // File Descriptor
int aio_lio_opcode; // Valid only for lio_listio (r/w/nop)
volatile void *aio_buf; // Data Buffer
size_t aio_nbytes; // Number of Bytes in Data Buffer
struct sigevent aio_sigevent; // Notification Structure

/* Internal fields */
...
};

aiocb相当于我们在标准I/O中的文件描述符,或者相当于网络I/O中的Socket。可以通过如下AIO API对一个aiocb进行操作:

API 介绍
aio_read 异步读操作
aio_error 检验异步请求状态
aio_return 获得一个已结束的I/O 的返回值
aio_write 异步写操作
aio_suspend 挂起当前进程,阻塞等待直到有一个或者多个异步请求结束(或者异常)
aio_cancel 取消一个异步请求
lio_listio 初始化一系列异步I/O操作

如下是一个简单的AIO调用:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <aio.h>

int main(int argc, char **argv)
{
int fd, ret;
struct aiocb read_aiocb;

fd = open("test", O_RDONLY);
if (fd < 0)
{
perror("open");
}

/* Zero out the aiocb structure (recommended) */
bzero((char *)&read_aiocb, sizeof(struct aiocb));
read_aiocb.aio_fildes = fd;
read_aiocb.aio_buf = malloc(100);
read_aiocb.aio_nbytes = 99;
read_aiocb.aio_offset = 0;

printf("calling aio...\n");
if (aio_read(&read_aiocb) < 0)
{
perror("aio_read");
}

printf("do something else...\n");

printf("use aio_suspend to block reading...\n");
struct aiocb *cblist[1];
bzero((char *)cblist, sizeof(cblist));
cblist[0] = &read_aiocb;

ret = aio_suspend(cblist, 1, NULL);

printf("get: %s\n", read_aiocb.aio_buf);

return 0;
}

同时,AIO也提供了通过信号以及通过回调的方式进行异步通知的方法。