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接口使用的更多相关文章

  1. shell脚本异步日志分析-接口耗时、可用率

    背景:现有日志接入日志报表大盘,为了避免作业高峰期间(双十一),系统也要观测系统整体情况,因此提出了观测近五分钟,接口成功率以及耗时等工具(默认统计最近五分钟,并进行结果汇总统计) 使用说明 前提:p ...

  2. java编程(2)——servlet和Ajax异步请求的接口编程(有调用数据库的数据)

    第一步: 1.为项目配置 Tomcat 为 server: 2.导入 mysql的jar包 到项目目录中: 第二步:编码 1.数据库连接类ConnectMysql.java代码: package co ...

  3. java编程(1)——servlet和Ajax异步请求的接口编程(没有调用数据库的数据)

    编程应用背景: 使用HttpServlet接口来编写一个动态登录的接口(需要在Tomcat容器发布) 登录的 LoginSample 类代码: package com.zhang.java; publ ...

  4. Apollo 8 — ConfigService 异步轮询接口的实现

    源码 Apollo 长轮询的实现,是通过客户端轮询 /notifications/v2 接口实现的.具体代码在 com.ctrip.framework.apollo.configservice.con ...

  5. 如何设计一个异步Web服务——接口部分

    需求比较简单,提供一个异步Web服务供使用者调用.比如说,某应用程序需要批量地给图片加lomo效果.由于加lomo效果这个操作非常消耗CPU资源,所以我们需要把这个加lomo效果的程序逻辑放到一台单独 ...

  6. Ajax异步调用http接口后刷新页面

    使用Ajax的目的就是提高页面响应速度,无需同步调用,无需整个页面刷新.这里直接在html中使用js来实现: 先获取XMLHttpRequest对象 var xmlHttp; //创建一个xmlHtt ...

  7. axios,vue-echarts, async, vue 图表数据处理; axios 跨域代理; 异步同步请求接口;生命周期函数

    1.vue-echarts 安装和组件引用 插件官网 https://github.com/ecomfe/vue-echarts 安装 npm install eacharts vue-echarts ...

  8. react中 如何异步展示后台接口的提示消息

    调用接口后,后台会返回这样的一段信息提示:{"errCode":400002,"errMsg":"字段校验异常","data&qu ...

  9. aio 系列函数是由 POSIX 定义的异步操作接口,可惜的是,Linux 下的 aio 操作,不是真正的操作系统级别支持的,它只是由 GNU libc 库函数在用户空间借由 pthread 方式实现的,而且仅仅针对磁盘类 I/O,套接字 I/O 不支持。

    30 | 真正的大杀器:异步I/O探索 https://time.geekbang.org/column/article/150780

随机推荐

  1. ngx.shared.DICT.set

    ngx.shared.DICT.set 原文: ngx.shared.DICT.set syntax: success, err, forcible = ngx.shared.DICT:set(key ...

  2. 用Fiddler模拟低速网络环境(弱网)

    原文链接:http://caibaojian.com/fiddler.html 有时候宽频网路用习惯了… 在开发的过程就比较少去考虑最佳化的问题… 但当有人反应说「你的网页好慢」 甚至当网路速度慢,会 ...

  3. ASP.NET MVC传递Model到视图的多种方式之通用方式的使用

    ASP.NET MVC传递Model到视图的多种方式总结——通用方式的使用 有多种方式可以将数据传递到视图,如下所示: ViewData ViewBag PartialView TempData Vi ...

  4. python -- 安装 django

    django-admin startproject 创建的文件名python3/python manage.py startapp 子项目名称python3/python manage.py runs ...

  5. 【Python】把文件名命名成canlendar.py竟然导致无法使用canlendar模块 附赠2020年月历

    这个bug困扰了我一阵,直到在 http://www.codingke.com/question/15489 找到了解决问题的钥匙,真是没想到居然是这个原因导致的. 下面是出错信息,可以看到只要目录下 ...

  6. android中SpannableString之富文本显示效果

    SpannableString其实和String一样,都是一种字符串类型,SpannableString可以直接作为TextView的显示文本,不同的是SpannableString可以通过使用其方法 ...

  7. 2013年各大小IT公司待遇,绝对真实,一线数据!(初版)

    本人西电硕士,根据今年找工作的情况以及身边同学的汇总,总结各大公司的待遇如下,吐血奉献给各位学弟学妹,公司比较全,你想去的公司不在这里面,基本上是无名小公司了:无名小公司有时也很给力哦以下绝对是各大公 ...

  8. ES6内建对象的继承

    在ES6之前, JS是无法通过继承的方式创建属于自己的特殊数组的, 也就是说可以使用原型链来继承数组的一些方法, 但是某些返回一个数组的方法返回的值还是一个Array的实例, 例如slice, len ...

  9. Spring Cloud(7):事件驱动(Stream)分布式缓存(Redis)及消息队列(Kafka)

    分布式缓存(Redis)及消息队列(Kafka) 设想一种情况,服务A频繁的调用服务B的数据,但是服务B的数据更新的并不频繁. 实际上,这种情况并不少见,大多数情况,用户的操作更多的是查询.如果我们缓 ...

  10. jQuery插件—获取URL参数

    做的项目中需要用到通过JS获取GET参数,上网找了一下,找到如下插件: 例如 当前你的URL是: http://www.xxx.com/index.php?test=1&kk=2 //如果想获 ...