前言
前几篇介绍了几种IO模型,今天介绍另一种IO模型——异步IO。
相对于前面的几种IO模型,异步IO在提交完IO操作请求后就立即返回,程序不需要等到IO操作完成再去做别的事情,具有非阻塞的特性。
当底层把IO操作完成后,可以给提交者发送信号,或者调用注册的回调函数,告知请求提交者IO操作已完成。
在信号处理函数或者回调函数中,可以使用异步IO接口来获得IO的完成情况,比如获取读写操作返回的字节数或错误码、读取的数据等。
相关接口
struct aiocb
结构体
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
:读写操作的数据缓冲区
aio_nbytes
:传输数据的字节数
aio_reqprio
:请求权限
aio_lio_opcode
:操作码,表示读还是写,LIO_READ代表读,LIO_WRITE代表写。
struct sigevent
结构体
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操作完成,内核会创建一个新线程执行一个回调函数,函数由sigev_notify_function
指定
sigev_signo
:指定的信号
sigev_notify_function
:回调函数
sigev_notify_attributes
:使用默认属性,一般设置为NULL
应用层异步IO读写函数:
#include < aio.h >
int aio_read(struct aiocb *aiocb);
int aio_write(struct aiocb *aiocb);
//返回值:成功返回0;失败返回-1
获取一个异步读、写或者同步操作的完成状态:
#include < aio.h >
int aio_error(const struct aiocb *aiocb);
调用aio_return
函数,可以用来判断异步IO的执行情况
#include < aio.h >
ssize_t aio_return(const struct aiocb *aiocb);
下面以一个实际例子说明异步IO的用法
应用层
#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);
}