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
随机推荐
- BZOJ2716天使玩偶
不会KD-tree怎么办?CQD硬搞. 建立正常的平面直角坐标系,首先我们只考虑在目标点左下角的点对目标点的贡献,由于左下点的横纵坐标都小于目标点,那么曼哈顿距离就可以化简了,绝对值去掉后,得到$x2 ...
- Windows下的apache maven安装与配置
去到官网http://maven.apache.org/download.cgi下载压缩包我选择的是二进制zip压缩文件. 解压并配置压缩文件的目录到MAVEN_HOME环境变量,添加解压文件下的bi ...
- go无缓冲通道
package main import ( "fmt" "math/rand" "sync" "time" ) //wg ...
- JavaScript数字精度丢失的一些问题
本文分为三个部分 JS 数字精度丢失的一些典型问题 JS 数字精度丢失的原因 解决方案(一个对象+一个函数) 一.JS数字精度丢失的一些典型问题 1. 两个简单的浮点数相加 1 0.1 + 0.2 ! ...
- Oralce JDBC jar包下载
下载地址:https://pan.baidu.com/s/1sU7gu4biigEAw-3Bu7yIOA 下载包中包括以下文件: ojdbc5.jarojdbc5dms.jarojdbc5dms_g. ...
- 阶段5 3.微服务项目【学成在线】_day17 用户认证 Zuul_17-身份校验-身份校验过虑器编写
5 身份校验 5.1 需求分析 本小节实现网关连接Redis校验令牌: 1.从cookie查询用户身份令牌是否存在,不存在则拒绝访问 2.从http header查询jwt令牌是否存在,不存在则拒绝访 ...
- 阶段5 3.微服务项目【学成在线】_day08 课程图片管理 分布式文件系统_06-分布式文件系统研究-fastDFS安装及配置文件说明
3 fastDFS入门 3.1fastDFS安装与配置 3.1.1 导入虚拟机 对fastDFS的安装过程不要求学生掌握,可以直接导入老师提供虚拟机. 1.使用Vmware打开虚拟机配置文件“Cent ...
- Mysql备份工具Xtrabackup
Xtrabackup是一个开源的免费的热备工具,在Xtrabackup包中主要有Xtrabackup和innobackupex两个工具.其中Xtrabackup只能备份InnoDB和XtraDB两种引 ...
- java nio Files.newDirectoryStream用法
try(DirectoryStream<Path> dirStream = Files.newDirectoryStream(Paths.get(directory,"*.ts& ...
- UIFontDownLoad ----动态下载系统提供的字体
程序运行结果如下 : 当点击对应单元格实现下载对应的字体. 控制台打印结果如下 : 2015-10-05 11:14:04.132 UIFontDownLoad[12721:86827] state ...