不知道你是否还记得线程中的 pthread_join 函数,它可以等待指定的线程完成结束后才会返回。同样的,在异步 IO 中,也有一个函数,但是它不是 aio_join,而是 aio_suspend,它会一直等待,直到指定的异步 IO 操作完成才返回。
1. aio_suspend
int aio_suspend(const struct aiocb * const aiocb_list[], int nitems, const struct timespec *timeout);
(1) 参数
这个函数参数看起来有点复杂,不过仔细看,实际上就是一个 aiocb 结构的指针数组。
- aiocb_list:就是一个数组,这个数组存储的元素的类型是 const struct aiocb* 类型。如果某个元素为 NULL,aio_suspend 会忽略它。
- nitems:aiocb_list 数组的大小。
- timeout:超时时间,这个参数前面已经遇到过 N 次了。设置成 NULL 表示永远等待,直到异步 IO 操作完成。
(2) 函数语义
aio_suspend 函数会阻塞调用线程,直到发生下面的事情:
- aiocb_list 中的一个或多个请求已完成。
- 收到信号,被信号打断。
- timeout 不空,指定的超时时间已过。
接下来看例子吧^_^
2. 实验
程序 my_aio_suspend 同样是对前面程序的修改。
- 代码
// my_aio_suspend.c
#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] = { 0 };
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;
ret = aio_read(&my_aiocb);
if (ret < 0) ERR_EXIT("aio_read");
// 为了传递给 aio_suspend 用,创建一个大小为 5 的数组
const struct aiocb* aio_list[5] = { NULL };
// 将其一中元素赋值,不一定是第 0 个,随便啊。
aio_list[0] = &my_aiocb;
// 只要 my_aiocb 这个异步读还没完成,aio_suspend 就会阻塞
ret = aio_suspend(aio_list, 5, NULL);
if (ret < 0) ERR_EXIT("aio_suspend");
puts("aio_suspend return");
// 实际上,这个 while 循环我们不可能看到它执行的。写在这里只是为了演示。
while(aio_error(&my_aiocb) == EINPROGRESS) {
puts("EINPROGRESS");
}
// 获取返回值。
ret = aio_return(&my_aiocb);
if (ret < 0) ERR_EXIT("aio_return");
printf("content: %s, return: %d\n", buf, ret);
return 0;
}
- 编译和运行
$ gcc my_aio_suspend.c -o my_aio_suspend -lrt
$ ./my_aio_suspend
图1 运行结果
启动程序后,程序首先会在 aio_suspend 处阻塞,在终端输入 hello 后,aio_suspend 就返回了。
3. 总结
- 掌握 aio_suspend 函数的语义和用法