小王,听说过AIO没?外国人,就这样,总是爱简写,简写的成果是咱们都不认识了。所谓AIO便是Asynchronous Input/Output异步输入/输出,基本思想是答应进程建议许多的I/O操作,而不必堵塞或等候任何操作的完结,稍后或在接收到I/O操作完结的告诉时,进程就能够检索I/O操作的成果。
“得得,你咋又跟我上起课来了呢,不是说好,今日CS吗?是不是跟我讲课特自傲啊“小王诉苦到。
“啊?不是吧,为啥这样呢,那你究竟听不听,别届时面试叫天天不灵叫地地不该的,别再找我哈”我愤慨的说。
"唉,你都这样说了,我也只能竖起耳朵好好听听了"看着小王极不甘愿的表情,我也觉得很不幸啊。
在异步非堵塞IO中,咱们是能够一起建议多个传输操作。这需求每个操作都有一个仅有的上下文,这样才干在它们完结时区别究竟是哪个传输操作完结了。在AIO中,
经过aiocb(AIO IO control Block)结构体进行区别,这个结构体如下:
struct aiocb {
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 offset */
struct sigevent aio_sigevent; /* Signal number and value */
int aio_lio_opcode; /* Operation to be performed */
};
从上边咱们能够看到,这个结构体包含了有关传输的一切信息,包含数据预备的用户缓冲区。在产生IO告诉时,aiocb结构就被用来仅有标识所完结的IO操作。
AIO系列API中主要有下边几个函数:
1.int aio_read(struct aiocb *aiocbp)
该函数恳求对一个有用的文件描述符进行异步读操作。在恳求进行排队之后会当即回来,假如履行成功,回来值就为0,过错则回来-1并设置errno的值。
2.int aio_write(struct aiocb *aiocbp)
该函数恳求一个异步写操作,它会当即回来阐明恳求现已进行排队,成功回来0,失利回来为-1,并设置相应的error值。
3.int aio_error(struct aiocb *aiocbp)
该函数用来确认恳求的状况,能够回来EINPROGRESS(阐明恳求没有完结),ECANCELLED(恳求被应用程序撤销了),-1(阐明产生了过错,详细过错原来由error记载)。
4.ssize_t aio_return(struct aiocb *aiocbp)
因为并没有堵塞在read调用上,所以咱们不能当即回来这个函数的回来状况,这是就要运用这个函数了,需求留意的是只需在aio_error调用确认恳求现已完结(或许
现已完结,也或许产生了过错)之后,才干调用这个函数,这个函数的回来值就相当于同步情况下read或write体系调用的回来值(所传输的字节数,假如产生过错,则回来-1)。
5.int aio_suspend(const struct aiocb *const cblist[], int n ,const struct timespec *timeout)
用户能够经过这个函数来来挂起(或堵塞)调用进程,直到异步恳求完结停止,此时会产生一个信号,或许产生其他超时操作。调用者供给了一个aiocb引证列表,其间任何一个完结都会导致给函数回来。
6.int aio_cancel(int fd ,struct aiocb *aiocbp)
该函数答应用户撤销对某个文件描述符履行的一个或一切的IO恳求。
假如要撤销一个恳求,用户需供给文件描述符和aiocb引证,假如这个恳求被成功撤销了,则回来AIO_CANCELED,假如该恳求完结了,回来AIO_NOTCANCELED.
假如要撤销对某个给定文件描述符的一切恳求,用户需求供给这个文件的描述符以及一个aiocbp的NULL引证,假如一切恳求被成功撤销了,则回来AIO_CANCELED
,只需至少有一个没被撤销,这个函数就回来AIO_NOT_CANCELED.假如没有一个恳求能够被撤销,该函数就会回来AIO_ALLDONE.
然后,能够运用aio_error来验证每个AIO恳求,假如某个恳求现已被回来了,那么aio_error就回来-1,而且error会被设置为ECANCELED.
7.int lio_listio(int mode ,struct aiocb *list[], int nent ,struct sigevent *sig)
这个操作使得用户能够在一个体系调用(一次内核上下文切换中发动很多的I/O操作)。其间,mode参数能够是LIO_WAIT或LIO_NOWAIT,前者会堵塞这个调用,直到一切的IO都完结停止,在操作进行排队之后,LIO_NOWAIT就会回来,list是一个aiocb引证的列表,最大元素的个数有nent界说的。假如list的元素为NULL,lio_lis
tio()将被疏忽。
光说理论也不可,是不?现在来点实践点的:
a)用户空间读例程:
#include
..
int fd, set;
struct aiocb my_aiocb;
fd = open("file.txt", O_RDONLY);
if( fd <0 )
{
perror("open");
}
//清零aiocb结构体
bzero((char *) &my_aiocb, sizeof(struct aiocb));
//为aiocb恳求分配数据缓冲区
my_aiocb.aio_buf = malloc(BUFSIZE + 1);
if(!my_aiocb.aio_buf)
perror("malloc");
//初始化aiocb的成员
my_aiocb.aio_fildes = fd;
my_aiocb.aio_nbytes = BUFSIZE;
my_aiocb.aio_offset = 0;
ret = aio_read(&my_aiocb);
if(ret < 0)
perror("aio_read");
while(aio_error(&my_aiocb) == EINPROGRESS)
;
if((ret = aio_return(&my_iocb)))
{
// 取得异步读的回来值
}
else
{
读失利,剖析errror
}
b)用户空间异步IO aio_suspend()函数运用例程
struct aioct *cblist(MAX_LIST)
//清零aioct结构链表
bzero((char *)cblist, sizeof(cblist));
//将一个或更多的aiocb放入aioct结构体链表
cblist[0] = &my_aiocb;
ret = aio_read( &my_aiocb);
ret = aio_suspend( cblist, MAX_LIST, NULL);
c)用户空间异步IO lio_list()函数运用例程
struct aiocb aiocb1,aiocb2;
struct aiocb *list[MAX_LIST];
…
//预备第一个aiocb
aiocb1.aio_fildes = fd;
aiocb1.aio_buf = malloc(BUFSIZE +1);
aiocb1.aio_nbytes = BUFSIZE;
aiocb1.aio_offset = next_offset;
aiocb1.aio_lio_opcode = LIO_READ;//异步读操作
…//预备多个aiocb
bzero((char *)list, sizeof(list));
//将aiocb填入链表
list[0] = &aiocb1;
list[1] = &aiocb2;
…
ret = lio_listio(LIO_WAIT, list, MAX_LIST, NULL); //建议很多IO操作
“涛哥,你说了这么多,如同也咋没和你说的驱动扯上联系呢”小王诉苦道。
“小王,不要急吗,我不是正计划说吗,瞧你着急性质,这样吧,你把今日的好好看看,咱们下集再说”…