POSIX 提供了函数 lio_listio 可以让我们一次性发起多个异步 IO 请求。

1. lio_listio

(1) 函数原型

int lio_listio(int mode, struct aiocb *const aiocb_list[], int nitems, struct

(2) 函数参数

  • mode

mode 有两个可选值:LIO_WAIT 和 LIO_NOWAIT.


含义

LIO_WAIT

lio_listio 会阻塞,直到所有的异步 IO 请求完成。此时参数 sevp 被忽略掉

LIO_NOWAIT

lio_listio 会立即返回,当所有异步 IO 请求完成后,会进行异步通知,通知的方式由参数 sevp 指定,该参数可以为 NULL,表示不需要异步通知。通知方式我们在下一讲就会说了。


  • aiocb_list 和 nitems
struct aiocb {
/* 下面所有字段依赖于具体实现 */

int aio_fildes; /* 文件描述符 */
off_t aio_offset; /* 文件偏移 */
volatile void *aio_buf; /* 缓冲区地址 */
size_t aio_nbytes; /* 传输的数据长度 */
int aio_reqprio; /* 请求优先级 */
struct sigevent aio_sigevent; /* 通知方法 */
int aio_lio_opcode; /* 仅被 lio_listio() 函数使用 */

/* Various implementation-internal fields not shown */

aiocb_list 就是 aiocb 结构体指针的数组,nitems 参数表示数组的大小。在使用 lio_listio 函数时,需要将 aiocb 中的 aio_lio_opcode 成员赋值,所以到这里,我们又学习到了一个新的成员。该成员告诉内核发起的是何中异步 IO 操作。aio_lio_opcode 的值可以为下面这些:


含义

LIO_READ

发起异步读操作

LIO_WRITE

发起异步写操作

LIO_NOP

表示忽略掉该 aiocb

还有最后一个参数,这里我们先不考虑它,在使用 lio_listio 函数的时候,将 sevp 设置为 NULL 就行了。

2. 实验

程序 my_aio_lio 修改了前面的代码,将 aio_read 函数替换成了 lio_listio 函数发起异步读请求。程序中并没有演示同时发起多个请求,只是发起了一个。实际上,一个你会了,多个也没什么问题,无非就是给数组赋几个值而已。

  • 代码
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <aio.h>
#include <strings.h>
#include <errno.h>

#define ERR_EXIT(msg) do { perror(msg); exit(1); } while(0)

int main() {
int fd, ret;
char buf[64];
struct aiocb my_aiocb;

bzero((char*)&my_aiocb, sizeof(struct aiocb));

my_aiocb.aio_buf = buf;
my_aiocb.aio_fildes = STDIN_FILENO;
my_aiocb.aio_nbytes = 64;
my_aiocb.aio_offset = 0;

// 注意这里多了一个成员的赋值,aio_lio_opcode 成员是专门给 lio_listio 函数用的。
my_aiocb.aio_lio_opcode = LIO_READ;

// 定义一个大小为 5 的数组,多大无所谓了,看你需求了。
struct aiocb* aio_list[5] = { NULL };
// 将你想发起的请求的控制块放到数组里,放哪个位置都行。这里我只发起了一个读操作。
aio_list[3] = &my_aiocb;

// 调用 lio_listio 发起读请求
ret = lio_listio(LIO_NOWAIT, aio_list, 5, NULL);


while(aio_error(&my_aiocb) == EINPROGRESS) {
write(STDOUT_FILENO, ".", 1);
sleep(1);
}


printf("content: %s\n", buf);

return 0;
}
  • 编译和运行
$ gcc my_aio_lio.c -o my_aio_lio -lrt
$ ./my_aio_lio


126-POSIX 异步IO(批量请求)_#include


图1 运行结果


程序启动后,在屏幕上开始打点,不用管它,直接输入 hello 然后回车。

3. 总结

  • 掌握 lio_listio 函数