前言
前幾篇介紹了幾種IO模型,今天介紹另一種IO模型——異步IO。
相對于前面的幾種IO模型,異步IO在提交完IO操作請求后就立即返回,程序不需要等到IO操作完成再去做別的事情,具有非阻塞的特性。
當?shù)讓影袸O操作完成后,可以給提交者發(fā)送信號,或者調(diào)用注冊的回調(diào)函數(shù),告知請求提交者IO操作已完成。
在信號處理函數(shù)或者回調(diào)函數(shù)中,可以使用異步IO接口來獲得IO的完成情況,比如獲取讀寫操作返回的字節(jié)數(shù)或錯誤碼、讀取的數(shù)據(jù)等。
相關(guān)接口
struct aiocb
結(jié)構(gòu)體
struct aiocb {
int aio_fildes; /* file descriptor */
off_t aio_offset; /* file offset for I/O */
volatile void *aio_buf; /* buffer for I/O */
size_t aio_nbytes; /* number of bytes tdo transfer */
int aio_reqprio; /* priority */
struct sigevent aio_sigevent; /* signal information */
int aio_lio_opcode; /* operation for list I/O */
};
aio_fildes
:操作的文件描述符
aio_offset
:偏移量,讀寫操作的起始位置
aio_buf
:讀寫操作的數(shù)據(jù)緩沖區(qū)
aio_nbytes
:傳輸數(shù)據(jù)的字節(jié)數(shù)
aio_reqprio
:請求權(quán)限
aio_lio_opcode
:操作碼,表示讀還是寫,LIO_READ代表讀,LIO_WRITE代表寫。
struct sigevent
結(jié)構(gòu)體
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 */
};
sigev_notify
:通知類型。SIGEV_NONE
表示不通知;SIGEV_SIGNAL
表示IO操作完成后,收到sigev_signo
指定的信號;SIGEV_THREAD
表示IO操作完成,內(nèi)核會創(chuàng)建一個新線程執(zhí)行一個回調(diào)函數(shù),函數(shù)由sigev_notify_function
指定
sigev_signo
:指定的信號
sigev_notify_function
:回調(diào)函數(shù)
sigev_notify_attributes
:使用默認屬性,一般設(shè)置為NULL
應(yīng)用層異步IO讀寫函數(shù):
#include < aio.h >
int aio_read(struct aiocb *aiocb);
int aio_write(struct aiocb *aiocb);
//返回值:成功返回0;失敗返回-1
獲取一個異步讀、寫或者同步操作的完成狀態(tài):
#include < aio.h >
int aio_error(const struct aiocb *aiocb);
調(diào)用aio_return
函數(shù),可以用來判斷異步IO的執(zhí)行情況
#include < aio.h >
ssize_t aio_return(const struct aiocb *aiocb);
下面以一個實際例子說明異步IO的用法
應(yīng)用層
#include < stdio.h >
#include < stdlib.h >
#include < string.h >
#include < sys/types.h >
#include < sys/stat.h >
#include < sys/ioctl.h >
#include < fcntl.h >
#include < errno.h >
#include < poll.h >
#include < linux/input.h >
#include < aio,h >
void aiow_completion_handler (sigval_t sigval)
{
int ret;
struct aiocb *req;
req = (struct aiocb *)sigval.sival_ptr;
if (aio_error(req) == 0) {
ret = aio_return (req) ;
printf ("aio write %d bytes\\n", ret);
}
return;
}
void aior_completion_handler ( sigval_t sigval )
{
int ret;
struct aiocb *req;
req = (struct aiocb * )sigval.sival_ptr;
if (aio_error (req > == 0 ) {
ret = aio_return (req);
if (ret)
printf ("aio read: %s\\n", (char * ) req- >aio_buf );
}
return;
}
int main(int argc, char *argv [])
{
int ret;
int fd;
struct aiocb aiow,aior;
fd = open("/dev/vser0", O_RDWR);
if (fd == -1)
goto fail;
memset (&aiow, 0, sizeof (aiow));
memset (&aior, 0, sizeof (aior));
aiow.aio_fildes = fd;
aiow.aio_buf = malloc(32);
strcpy((char *)aiow.aio_buf,"aio test");
aiow.aio_nbytes = strlen ( (char * ) aiow.aio_buf ) + 1;
aiow.a*io_of f set = 0;
aiow.aio_sigevent.sigev_notify = SIGEV_THREAD;
aiow.aio_sigevent.sigev_notify_function = aiow_completion_handler;
aiow.aio_sigevent.sigev_notify_attributes = NULL;
aiow.aio_sigevent.sigev_value.sival_ptr = &aiow;
aior.aio_fildes = fd;
aior.aio_buf = malloc (32);
aior.aio_nbytes = 32;
aior.aio_offset = 0;
aior.aio_sigevent ?sigev_notify = SIGEV_THREAD;
aior.aio_sigevent.sigev_notify_function = aior_completion_handler;
aior.aio_sigevent.sigev_notify_attributes = NULL;
aior.aio_sigevent.sigev_value.sival_ptr = &aior;
while(1){
if(aio_write(&aiow) == -1)
goto fail;
if(aio_read(&aior) == -1)
goto fail;
sleep(1);
}
fail:
perror("aio test");
exit(EXIT_FAILURE);
}