POSIX 提供了函数 lio_listio 可以让我们一次性发起多个异步 IO 请求。
1. lio_listio
(1) 函数原型
int lio_listio(int mode, struct aiocb *const aiocb_list[], int nitems, struct sigevent *sevp);
(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. 实验
修改了前面的代码,将 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; // 告诉内核,缓冲区大小只有 64
my_aiocb.aio_offset = 0; // 告诉内核,从偏移为 0 的地方开始读
//注意这里多了一个成员的赋值,aio_lio_opcode成员是专门给lio_listio函数使用的
my_aiocb.aio_lio_opcode=LIO_READ;
struct aiocb *aio_list[5]={NULL};
aio_list[2]=&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;
}
编译与运行
图一运行结果
程序启动后,在屏幕上开始打点,不用管它,直接输入 hello 然后回车。
3. 总结
- 掌握 lio_listio 函数
转自:https://blog.csdn.net/q1007729991/article/details/68064840