POSIX异步I/O接口使用
POSIX1003.1b 实时扩展协议规定的标准异步 I/O 接口,即 aio_read 函数、 aio_write 函数、aio_fsync 函数、aio_cancel 函数、aio_error 函数、aio_return 函数、aio_suspend函数和 lio_listio 函数。这组 API 用来操作异步 I/O。
异步 I/O 是针对同步 I/O 提出的概念,它不需要线程等待 I/O 结果,而只需要请求进行传输,然后系统会自动完成 I/O 传输,结束或者出现错误时会产生相应的 I/O 信号,用户程序只需要设置好对应的信号陷入函数,即可处理一个异步 I/O 事件。
#man aio
The POSIX AIO interface consists of the following functions:
aio_read() Enqueue a read request. This is the asynchronous analog of read().
aio_write() Enqueue a write request. This is the asynchronous analog of write().
aio_fsync() Enqueue a sync request for the I/O operations on a file descriptor. This is the asynchronous analog of fsync() and fdatasync().
aio_error() Obtain the error status of an enqueued I/O request.
aio_return() Obtain the return status of a completed I/O request.
aio_suspend() Suspend the caller until one or more of a specified set of I/O requests completes.
aio_cancel() Attempt to cancel outstanding I/O requests on a specified file descriptor.
lio_listio() Enqueue multiple I/O requests using a single function call.
The aiocb ("asynchronous I/O control block") structure defines parameters that control an I/O operation. An argument of this type is employed with all of the functions listed
above. This structure has the following form:
#include <aiocb.h>
struct aiocb {
/* The order of these fields is implementation-dependent */
int aio_fildes; /* File descriptor */
off_t aio_offset; /* File offset */
volatile void *aio_buf; /* Location of buffer */
size_t aio_nbytes; /* Length of transfer */
int aio_reqprio; /* Request priority */
struct sigevent aio_sigevent; /* Notification method */
int aio_lio_opcode; /* Operation to be performed;
lio_listio() only */
/* Various implementation-internal fields not shown */
};
struct sigevent{
int sigev_notify; // notify type
int sigev_signo; // signal number
union sigval sigev_value; // notify argument
void (*sigev_notify_function)(union sigval); // notify function
pthread_attr_t *sigev_notify_attributes; // notify attrs
};
在 aiocb 结构中,aio_fildes 字段表示被打开用来读或写的文件描述符。
读或写操作从 aio_offset 指定的偏移量开始(注意,异步 I/O 操作必须显示地指定偏移量。只要不在同一个进程里把异步 I/O 函数和传统 I/O 函数混在一起用在同一个文件上,异步 I/O 接口是不会影响操作系统维护的文件偏移量的。
另外,如果使用异步 I/O 接口向一个以追加模式打开的文件中写入数据,aio_offset 字段会被忽略)。
读写数据的操作都是在 aio_buf 指定的缓冲区中进行,aio_nbytes 字段则包含了要读写的字节数。
aio_reqprio 为异步 I/O 请求提示顺序(但系统对该顺序的控制力有限,因此不一定遵循)。
LIO_NOP 没有传输请求
LIO_READ 请求一个读操作
LIO_WRITE 请求一个写操作
LIO_SYNC 请求异步 I/O 同步
aio_lio_opcode 字段只能用于基于列表的异步 I/O(见下)。aio_sigevent 使用 sigevent 结构来控制在 I/O 事件完成后,如何通知应用程序。
在 sigevent 结构中,sigev_notify 字段控制通知的类型,其取值可能是以下 3 个中的一个。
()SIGEV_NONE:
异步 I/O 请求完成后,不通知进程。
()SIGEV_SIGNAL:
异步 I/O 请求完成后,产生由 sigev_signo 字段指定的信号。如果应用程序已选择捕捉信号,且在建立信号处理程序时指定了 SA_SIGINFO 标志,那么该信号将被入队(如果实现支持排队信号)。
信号处理程序会传送给一个 siginfo 结构,该结构的 si_value 字段被设置为 sigev_value(如果使用了 SA_SIGINFO 标志)。
()SIGEV_THREAD:
当异步 I/O 请求完成时,由 sigev_notify_function 指定的函数会被调用,sigev_value 字段被作为它的唯一参数传入。
除非 sigev_notify_attributes 字段被设置为 pthread 属性结构的地址,且该结构指定了另一个线程属性,否则该函数将在分离状态下的一个单独的线程中执行。
进行异步 I/O 之前需要先初始化 AIO 控制块。aio_read 和 aio_write 函数可分别用来进行异步读和异步写操作。
调用 aio_read 函数和 aio_write 函数成功之后,异步 I/O 请求便已经被操作系统放入等待处理的队列中了。这些返回值与实际 I/O 操作的结果没有任何关系,如果需要查看函数的返回状态可调用 aio_error 函数。
如果想强制所有等待中的异步操作不等待而写入存储中,可以建立一个 AIO 控制块并调用 aio_fsync 函数。
aio_fsync 在安排了同步后便返回,在异步同步操作完成前,数据不会被持久化。AIO 控制块中的 aio_fields 字段指定了其异步写操作被同步的文件。如果 op 参数被设置为 O_DSYNC,那么操作执行起来就会像调用了 fdatasync 一样。否则,如果 op 参数被设置为 O_SYNC,则操作执行起来就会像调用了 fsync 一样。
aio_error 的返回值为下面 4 种情况中的一种。
():表示异步操作成功完成,需要调用 aio_return 函数来获取操作返回值。
()-:表示对 aio_error 的调用失败,这可以通过查看 errno 来获知失败原因。
()EINPROGRESS:表示异步读、写或同步操作仍在等待。
()其他情况:其他任何的返回值是相关的异步操作失败返回的错误码。
直到异步操作完成之前,都需要小心不要调用 aio_return 函数,否则结果是未定义的。而且还要小心对每个异步操作只调用一次 aio_return,因为一旦调用了该函数,操作系统就可以释放掉包含了 I/O 操作返回值的记录。如果 aio_return 本身失败,就会返回 -1,并设置 errno。否则其他情况下,它将直接返回 read、write 或 fsync 被成功调用时的结果。
执行 I/O 操作时,如果还有其他事务要处理而不想被 I/O 操作阻塞,就可以使用异步 I/O。但如果在完成了所有事务后还有异步操作未完成时,就可以调用 aio_suspend 函数来阻塞进程,直到操作完成。
RETURN VALUE
If this function returns after completion of one of the I/O requests specified in aiocb_list, is returned. Otherwise, - is returned, and errno is set to indicate the error. ERRORS
EAGAIN The call timed out before any of the indicated operations had completed. EINTR The call was ended by signal (possibly the completion signal of one of the operations we were waiting for); see signal().
而当还有不想再完成的等待中的异步 I/O 操作时,可以尝试用 aio_cancel 函数来取消它们。
aio_cancel 会返回以下情况中的一种:
AIO_CANCELED 所有请求的操作已被取消
All requests were successfully canceled. AIO_NOTCANCELED 至少有一个请求操作没被取消
At least one of the requests specified was not canceled because it was in progress. In this case, one may check the status of individual requests using aio_error(). AIO_ALLDONE 在请求取消之前已经完成
All requests had already been completed before the call. - An error occurred. The cause of the error can be found by inspecting errno.
以下是一个来自 man 手册的 例程
#include <fcntl.h>
#include <stdlib.h>
#include <unistd.h>
#include <stdio.h>
#include <errno.h>
#include <aio.h>
#include <signal.h> #define BUF_SIZE 20 /* Size of buffers for read operations */ #define errExit(msg) do { perror(msg); exit(EXIT_FAILURE); } while (0) #define errMsg(msg) do { perror(msg); } while (0) struct ioRequest { /* Application-defined structure for tracking
I/O requests */
int reqNum;
int status;
struct aiocb *aiocbp;
}; static volatile sig_atomic_t gotSIGQUIT = ;
/* On delivery of SIGQUIT, we attempt to
cancel all outstanding I/O requests */ static void /* Handler for SIGQUIT */
quitHandler(int sig)
{
gotSIGQUIT = ;
} #define IO_SIGNAL SIGUSR1 /* Signal used to notify I/O completion */ static void /* Handler for I/O completion signal */
aioSigHandler(int sig, siginfo_t *si, void *ucontext)
{
if (si->si_code == SI_ASYNCIO) {
write(STDOUT_FILENO, "I/O completion signal received\n", ); /* The corresponding ioRequest structure would be available as
struct ioRequest *ioReq = si->si_value.sival_ptr;
and the file descriptor would then be available via
ioReq->aiocbp->aio_fildes */
}
} int
main(int argc, char *argv[])
{
struct ioRequest *ioList;
struct aiocb *aiocbList;
struct sigaction sa;
int s, j;
int numReqs; /* Total number of queued I/O requests */
int openReqs; /* Number of I/O requests still in progress */ if (argc < ) {
fprintf(stderr, "Usage: %s <pathname> <pathname>...\n",
argv[]);
exit(EXIT_FAILURE);
} numReqs = argc - ; /* Allocate our arrays */ ioList = calloc(numReqs, sizeof(struct ioRequest));
if (ioList == NULL)
errExit("calloc"); aiocbList = calloc(numReqs, sizeof(struct aiocb));
if (aiocbList == NULL)
errExit("calloc"); /* Establish handlers for SIGQUIT and the I/O completion signal */ sa.sa_flags = SA_RESTART;
sigemptyset(&sa.sa_mask); sa.sa_handler = quitHandler;
if (sigaction(SIGQUIT, &sa, NULL) == -)
errExit("sigaction"); sa.sa_flags = SA_RESTART | SA_SIGINFO;
sa.sa_sigaction = aioSigHandler;
if (sigaction(IO_SIGNAL, &sa, NULL) == -)
errExit("sigaction"); /* Open each file specified on the command line, and queue
a read request on the resulting file descriptor */ for (j = ; j < numReqs; j++) {
ioList[j].reqNum = j;
ioList[j].status = EINPROGRESS;
ioList[j].aiocbp = &aiocbList[j]; ioList[j].aiocbp->aio_fildes = open(argv[j + ], O_RDONLY);
if (ioList[j].aiocbp->aio_fildes == -)
errExit("open");
printf("opened %s on descriptor %d\n", argv[j + ],
ioList[j].aiocbp->aio_fildes); ioList[j].aiocbp->aio_buf = malloc(BUF_SIZE);
if (ioList[j].aiocbp->aio_buf == NULL)
errExit("malloc"); ioList[j].aiocbp->aio_nbytes = BUF_SIZE;
ioList[j].aiocbp->aio_reqprio = ;
ioList[j].aiocbp->aio_offset = ;
ioList[j].aiocbp->aio_sigevent.sigev_notify = SIGEV_SIGNAL;
ioList[j].aiocbp->aio_sigevent.sigev_signo = IO_SIGNAL;
ioList[j].aiocbp->aio_sigevent.sigev_value.sival_ptr =
&ioList[j]; s = aio_read(ioList[j].aiocbp);
if (s == -)
errExit("aio_read");
} openReqs = numReqs; /* Loop, monitoring status of I/O requests */ while (openReqs > ) {
sleep(); /* Delay between each monitoring step */ if (gotSIGQUIT) { /* On receipt of SIGQUIT, attempt to cancel each of the
outstanding I/O requests, and display status returned
from the cancellation requests */ printf("got SIGQUIT; canceling I/O requests: \n"); for (j = ; j < numReqs; j++) {
if (ioList[j].status == EINPROGRESS) {
printf(" Request %d on descriptor %d:", j,
ioList[j].aiocbp->aio_fildes);
s = aio_cancel(ioList[j].aiocbp->aio_fildes,
ioList[j].aiocbp);
if (s == AIO_CANCELED)
printf("I/O canceled\n");
else if (s == AIO_NOTCANCELED)
printf("I/O not canceled\n");
else if (s == AIO_ALLDONE)
printf("I/O all done\n");
else
errMsg("aio_cancel");
}
} gotSIGQUIT = ;
} /* Check the status of each I/O request that is still
in progress */ printf("aio_error():\n");
for (j = ; j < numReqs; j++) {
if (ioList[j].status == EINPROGRESS) {
printf(" for request %d (descriptor %d): ",
j, ioList[j].aiocbp->aio_fildes);
ioList[j].status = aio_error(ioList[j].aiocbp); switch (ioList[j].status) {
case :
printf("I/O succeeded\n");
break;
case EINPROGRESS:
printf("In progress\n");
break;
case ECANCELED:
printf("Canceled\n");
break;
default:
errMsg("aio_error");
break;
} if (ioList[j].status != EINPROGRESS)
openReqs--;
}
}
} printf("All I/O requests completed\n"); /* Check status return of all I/O requests */ printf("aio_return():\n");
for (j = ; j < numReqs; j++) {
ssize_t s; s = aio_return(ioList[j].aiocbp);
printf(" for request %d (descriptor %d): %zd\n",
j, ioList[j].aiocbp->aio_fildes, s);
} exit(EXIT_SUCCESS);
}
ref:https://blog.csdn.net/aisxyz/article/details/84915025
POSIX异步I/O接口使用的更多相关文章
- shell脚本异步日志分析-接口耗时、可用率
背景:现有日志接入日志报表大盘,为了避免作业高峰期间(双十一),系统也要观测系统整体情况,因此提出了观测近五分钟,接口成功率以及耗时等工具(默认统计最近五分钟,并进行结果汇总统计) 使用说明 前提:p ...
- java编程(2)——servlet和Ajax异步请求的接口编程(有调用数据库的数据)
第一步: 1.为项目配置 Tomcat 为 server: 2.导入 mysql的jar包 到项目目录中: 第二步:编码 1.数据库连接类ConnectMysql.java代码: package co ...
- java编程(1)——servlet和Ajax异步请求的接口编程(没有调用数据库的数据)
编程应用背景: 使用HttpServlet接口来编写一个动态登录的接口(需要在Tomcat容器发布) 登录的 LoginSample 类代码: package com.zhang.java; publ ...
- Apollo 8 — ConfigService 异步轮询接口的实现
源码 Apollo 长轮询的实现,是通过客户端轮询 /notifications/v2 接口实现的.具体代码在 com.ctrip.framework.apollo.configservice.con ...
- 如何设计一个异步Web服务——接口部分
需求比较简单,提供一个异步Web服务供使用者调用.比如说,某应用程序需要批量地给图片加lomo效果.由于加lomo效果这个操作非常消耗CPU资源,所以我们需要把这个加lomo效果的程序逻辑放到一台单独 ...
- Ajax异步调用http接口后刷新页面
使用Ajax的目的就是提高页面响应速度,无需同步调用,无需整个页面刷新.这里直接在html中使用js来实现: 先获取XMLHttpRequest对象 var xmlHttp; //创建一个xmlHtt ...
- axios,vue-echarts, async, vue 图表数据处理; axios 跨域代理; 异步同步请求接口;生命周期函数
1.vue-echarts 安装和组件引用 插件官网 https://github.com/ecomfe/vue-echarts 安装 npm install eacharts vue-echarts ...
- react中 如何异步展示后台接口的提示消息
调用接口后,后台会返回这样的一段信息提示:{"errCode":400002,"errMsg":"字段校验异常","data&qu ...
- aio 系列函数是由 POSIX 定义的异步操作接口,可惜的是,Linux 下的 aio 操作,不是真正的操作系统级别支持的,它只是由 GNU libc 库函数在用户空间借由 pthread 方式实现的,而且仅仅针对磁盘类 I/O,套接字 I/O 不支持。
30 | 真正的大杀器:异步I/O探索 https://time.geekbang.org/column/article/150780
随机推荐
- mysql和mssql数据库快速创建表格 五
* into testAAA FROM tbl_User --sqlserver方法一复制表结构 select * into testAAA FROM tbl_User --sqlserver复制表结 ...
- 【hadoop环境问题】namenode无法启动问题解决
[问题背景] 要在自己的阿里云上搭伪分布式,用来复习和强化hive相关的知识,在执行脚本 sh start-dfs.sh后,jps后: 然后查看name的日志,报错如下: [解决方法] 网上的很多方法 ...
- IdentityServer4入门四:应用Implicit模式保护网站(上)
我们先新增一个网站,名为“ClientMvc",也是asp.net core Web应用程序(模型视图控制器) 使用nuget安装以下引用 Microsoft.AspNetCore.Auth ...
- 迭代器Iterator、for循环遍历、泛型
java.util.Collection接口 是集合的最顶层的接口,定义了集合共性的方法 接口无法直接创建对象,使用多态的方式创建对象 Collection<集合中的数据类型(泛型)> c ...
- Leetcode题目461:汉明距离(位运算-简单)
题目描述: 两个整数之间的汉明距离指的是这两个数字对应二进制位不同的位置的数目. 给出两个整数 x 和 y,计算它们之间的汉明距离. 注意:0 ≤ x, y < 231. 示例: 输入: x = ...
- IDEA的版本控制
参考:https://blog.csdn.net/qq_35246620/article/details/70792861 1.从远程仓库下载项目 2.提交项目到远程仓库
- ab 压测
Linux学习14-ab报错apr_pollset_poll: The timeout specified has expired (70007) 前言 使用ab压力测试时候出现报错apr_polls ...
- VUE钩子函数created与mounted区别
created:在模板渲染成html前调用,即通常初始化某些属性值,然后再渲染成视图. mounted:在模板渲染成html后调用,通常是初始化页面完成后,再对html的dom节点进行一些需要的操作.
- Mac下安装python2和python3共存
一般是python2默认安装了,python3没有安装,这时候一般使用命令:brew install python3 进行安装 这里有个基础知识要记录一下,就是不同方法安装python的路径是不一样的 ...
- 阶段5 3.微服务项目【学成在线】_day07 课程管理实战_01-我的课程-需求分析与PageHelper技术
1 我的课程 1.1需求分析 课程添加完成后可通过我的课程进入课程修改页面,此页面显示我的课程列表,如下图所示,可分页查询. 注意:由于课程图片服务器没有搭建,这里在测试时图片暂时无法显示. 上边的查 ...