不知道你是否还记得线程中的 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. 实验
同样是对前面程序的修改。
#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 的地方开始读
// 发起异步读操作,立即返回。你并不知道何时 buf 中会有数据
ret = aio_read(&my_aiocb);
if (ret < 0) ERR_EXIT("aio_read");
//为了传递aio_suspend用,创建一个大小为5的数组
const struct aiocb *aio_list[5]={NULL};
//将其中一元素赋值,不一定是第一个
aio_list[4]=&my_aiocb;
ret=aio_suspend(aio_list,5,NULL);
if(ret<0)
{
ERR_EXIT("aio_suspend");
}
printf("aio_suspend return\n");
// 不断的检查异步读的状态,如果返回 EINPROGRESS,说明异步读还没完成
// 轮询检查状态是一种很笨的方式,其实可以让操作系统用信号的方式来通知,或者让操作系统完成读后主 动创建一个线程执行。
while(aio_error(&my_aiocb) == EINPROGRESS) {
puts("EINPROGRESS");
}
ret=aio_return(&my_aiocb);
if(ret<0)
{
ERR_EXIT("aio_return");
}
// 打印缓冲区内容,你并不知道内核是什么时候将缓冲区中的 hello 复制到你的 buf 中的。
printf("content: %s,return:%d\n", buf,ret);
return 0;
}
编译与运行
图1运行结果
启动程序后,程序首先会在 aio_suspend 处阻塞,在终端输入hello world 后,aio_suspend 就返回了。
3. 总结
- 掌握 aio_suspend 函数的语义和用法
转自:https://blog.csdn.net/q1007729991/article/details/68060889