Unix环境变量--POSIX异步I/O

异步 I/O 是针对同步 I/O 提出的概念,它不需要线程等待 I/O 结果,而只需要请求进行传输,然后系统会自动完成 I/O 传输,结束或者出现错误时会产生相应的 I/O 信号,用户程序只需要设置好对应的信号陷入函数,即可处理一个异步 I/O 事件。

        #include <aiocb.h>
           struct aiocb {
               int             aio_fildes;     /* 用户用来读或者写的文件描述符 */
               off_t           aio_offset;     /* 开始读写的偏移量 */
               volatile void  *aio_buf;        /* 用于读或写的缓冲区 */
               size_t          aio_nbytes;     /* 操作的字符个数 */
               int             aio_reqprio;    /* 操作的优先级,但不一定生效 */
               struct sigevent aio_sigevent;   /* 异步IO完成后,通知进程的方式,详细见下面 */
               int             aio_lio_opcode; /* Operation to be performed;lio_listio() only */

           };

            struct sigevent{
                int             sigev_notify;    // 通知类型
                int             sigev_signo;     // 信号值
                union sigval    sigev_value;     // 回调函数的参数
                void (*sigev_notify_function)(union sigval);    // 回调函数
                pthread_attr_t *sigev_notify_attributes;        // 
            };

                       sigev_notify的取值有以下三种:

                       SIGEV_NONE:异步I/O请求完成后,不通知进程

                       SIGEV_SIGNAL:异步I/O请求完成后,产生由sigev_signo字段指定的信号。如果应用程序已选择捕捉信号,且在建立信号处理程序的时候指定了SA_SIGINFO标志,那么该信号将被入队(如果实现支持排队信号),信号处理程序会传送给一个siginfo结构,该结构的si_value字段被设置为sigev_value

                       SIGEV_THREAD 当异步I/O请求完成后,由sigev_notify_function指定的函数被调用,sigev_value是唯一的参数。除非sigev_notify_attributes字段被设定为pthread属性结构的地址,且结构指定了另外的线程属性,否则该函数将在分离状态下的单独的线程下执行。

    #include <aio.h>

    int aio_read(struct aiocb *aiocbp);
    int aio_write(struct aiocb *aiocbp);
    int aio_fsync(int op,struct aiocb *aiocbp);
    int aio_error(const struct aiocb *aiocbp);
    ssize_t aio_return(const struct aiocb *aiocbp);
    int aio_suspend(const struct aiocb *list,int nent,const struct timespec* timeout);
    int aio_cancel(int op,struct aiocb *aiocbp);

异步IO的操作流程大概如下:

(1)使用aio_read()或者aio_write()将操作请求放入到等待处理的队列中。这两个函数的返回值与实际操作结果并没有任何关系

(2)aio_fsync()函数用于将aio_write()的写请求同步到硬盘,op指定异步的方式,若op为O_DSYNC则表示只是更新硬盘文件内容,若op为O_SYNC则表示等待实际I/O结束才返回,从而确保修改过的块立即写到硬盘上。

(3)aio_error()是为了获取到一个异步读写或同步的状态,返回值有以下几种情况:

     0:异步操作完成,可以调用aio_return()函数获取操作返回值

     -1:aio_error函数调用失败

      EINPROGRESS:异步读写或同步仍未完成

 (4)如果aio_error()获取到异步操作已经完成,则可以使用函数aio_return()获取异步操作的返回值,此时必须确保异步读写或同步已经完成,函数调用失败返回-1.

 (5)如果在完成了所有事务之后,异步IO仍然没有完成,可以使用aio_suspend()阻塞进程,直到所有的操作完成,其中list是AIO控制块数组,nent表明了数组的个数。aio_suspend()的返回值有三种:(1)如果被信号中断,它将返回-1,并将errno设置为EINTR.(2)如果timeout超时,它将返回-1,并将errno设置为EAGAIN,timeout为NULL则表示不限时(3)如果返回值为0,则表示所有异步IO都已经完成,将不阻塞直接返回

(6)当我们不想等待异步IO的操作时,可以使用函数aio_cancel()来尝试取消他们。fd为操作的文件描述符,aiocbp为操作的数据块,如果aiocbp为NULL,则表示取消fd上面的所有异步IO操作。返回值有以下4种情况:

   AIO_ALLDONE:所有异步IO操作在尝试取消他们之前都已经完成

   AIO_CANCELED:所有要求的操作已被取消

   AIO_NOTCANCELED:至少一个操作请求没有被取消。

   -1:函数调用失败

还有一个函数,它既可以以同步接口调用,也可以以异步接口调用。

#include <aio.h>
int aio_listio(int mode,struct aiocb* list,int nent,struct sigevent* sigev);

mode参数决定该函数是异步还是同步IO,如果该参数被设置为LIO_WAIT,则表示该函数是同步的,即在所有操作完成后,函数才返回,此时sigev将被忽略。如果被设置为LIO_NOWAIT,函数将是异步IO,即只是将访问请求放在队列中即返回,在所有IO结束后,按照sigev参数指定的方式被异步通知,如果不想被通知,可以将sigev设置为NULL。注意,每个控制块都有自己在完成后的通知方式,这里的sigev是另外附加的,它是是所有操作完成后,进行通知。

list是控制块的列表,nent表示个数。

猜你喜欢

转载自blog.csdn.net/Chiang2018/article/details/105447217
今日推荐