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. ICEM-轴(周期复制网格)

    原视频下载地址:https://yunpan.cn/cqMnfpqQQdZZI  访问密码 802b

  2. java集合——Map

    声明:以下内容都是来自网络总结,将会参考很多,没有声明转载来源. 一.Map接口 1.HashMap HashMap和HashTable的区别:http://blog.csdn.net/shohoku ...

  3. iframe窗口嵌套,子窗口跳转重叠在父窗口的问题

    window.top //最顶层窗口 window.self //当前窗口 window.parent //父级窗口 "window.location.href"."lo ...

  4. perl 语法速查 | 模块安装

    perl -MCPAN -e shell install Bio::SeqIO 或者直接perl -MCPAN -e 'install Excel::Writer::XLSX' 用cpan装不上,编译 ...

  5. OpenJudge计算概论-整数的个数

    /*========================================================== 整数的个数 总时间限制: 1000ms 内存限制: 65536kB 描述 给定 ...

  6. Java中运行动态脚本

    这里主要总结Java中集成Groovy的应用. Groovy可以与Java完美集成来扩展我们的应用,比如替代Java+jexl实现算式表达式计算或其它功能.在Ofbiz中也集成了Groovy来执行一些 ...

  7. Vuex 通俗版教程告诉你Vuex怎么用

    写在文前: 最近一直在用vue开发项目,写来写去就是那么些方法,对于简单的项目一些常用的vue方法足以解决,但是涉及到页面状态,权限判断等一些复杂的传值,vuex是必须的.对于vuex也运用一段时间, ...

  8. BitmapFactory: inSampleSize 的一些思考

    一. BitmapFactory.Options 中inSampleSize的取值问题 关于inSampleSize的取值问题Google已经给出了一个推荐的算法:(https://developer ...

  9. JS-数组与伪数组

    数组与伪数组 把符合以下条件的对象称为伪数组: 具有length属性 按索引方式存储数据 不具有数组的push,pop等方法 伪数组(类数组):无法直接调用数组方法或期望length属性有什么特殊的行 ...

  10. HTML5 地理位置定位API(3)

    HTML5 地理位置定位实例 这篇文章主要为大家介绍了HTML5地理定位的方法,实例讲述了html5获取坐标完整实现过程, 并对比不同浏览器运行效果给出参考结果,需要的朋友可以参考下 本文实例讲述了h ...