|
马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。
您需要 登录 才可以下载或查看,没有帐号?立即注册
x
经常看到有人问用什么版本的linux好,其实只要你认真学习无论什么版本都挺好的。
在DirectIO形式下,异步长短常有需要的(由于绕过了pagecache,间接和磁盘交互)。linuxNativeAIO恰是基于这类场景计划的,详细的先容见:KernelAsynchronousI/O(AIO)SupportforLinux。上面我们就来剖析一下AIO编程的相干常识。
堵塞形式下的IO历程以下:
intfd=open(constchar*pathname,intflags,mode_tmode);
ssize_tpread(intfd,void*buf,size_tcount,off_toffset);
ssize_tpwrite(intfd,constvoid*buf,size_tcount,off_toffset);
intclose(intfd);
由于全部历程会守候read/write的前往,以是不必要任何分外的数据布局。但异步IO的头脑是:使用程序不克不及堵塞在高贵的体系挪用上让CPU睡年夜觉,而是将IO操纵笼统成一个个的义务单位提交给内核,内核完成IO义务后将了局放在使用程序能够取到的中央。如许在底层做I/O的这段工夫内,CPU能够往干其他的盘算义务。但异步的IO义务批量的提交和完成,必需有本身可形貌的布局,最主要的两个就是iocb和io_event。
libaio中的structs
structiocb{
void*data;/*Returnintheiocompletionevent*/
unsignedkey;/*ruseinidentifyingiorequests*/
shortaio_lio_opcode;
shortaio_reqprio;
intaio_fildes;
union{
structio_iocb_commonc;
structio_iocb_vectorv;
structio_iocb_pollpoll;
structio_iocb_sockaddrsaddr;
}u;
};
structio_iocb_common{
void*buf;
unsignedlongnbytes;
longlongoffset;
unsignedflags;
unsignedresfd;
};
iocb是提交IO义务时用到的,能够完全地形貌一个IO哀求:
data是留给用来自界说的指针:能够设置为IO完成后的callback函数;
aio_lio_opcode暗示操纵的范例:IO_CMD_PWRITE|IO_CMD_PREAD;
aio_fildes是要操纵的文件:fd;
io_iocb_common中的buf,nbytes,offset分离纪录的IO哀求的membuffer,巨细和偏移。
structio_event{
void*data;
structiocb*obj;
unsignedlongres;
unsignedlongres2;
};
io_event是用来形貌前往了局的:
obj就是之条件交IO义务时的iocb;
res和res2来暗示IO义务完成的形态。
libaio供应的API和完成IO的历程
libaio供应的API有:io_setup,io_submit,io_getevents,io_destroy。
1.创建IO义务
intio_setup(intmaxevents,io_context_t*ctxp);
io_context_t对应内核中一个布局,为异步IO哀求供应高低文情况。注重在setup前必需将io_context_t初始化为0。
固然,这里也必要open必要操纵的文件,注重设置O_DIRECT标记。
2.提交IO义务
longio_submit(aio_context_tctx_id,longnr,structiocb**iocbpp);
提交义务之前必需先添补iocb布局体,libaio供应的包装函数申明了必要完成的事情:
voidio_prep_pread(structiocb*iocb,intfd,void*buf,size_tcount,longlongoffset)
{
memset(iocb,0,sizeof(*iocb));
iocb->aio_fildes=fd;
iocb->aio_lio_opcode=IO_CMD_PREAD;
iocb->aio_reqprio=0;
iocb->u.c.buf=buf;
iocb->u.c.nbytes=count;
iocb->u.c.offset=offset;
}
voidio_prep_pwrite(structiocb*iocb,intfd,void*buf,size_tcount,longlongoffset)
{
memset(iocb,0,sizeof(*iocb));
iocb->aio_fildes=fd;
iocb->aio_lio_opcode=IO_CMD_PWRITE;
iocb->aio_reqprio=0;
iocb->u.c.buf=buf;
iocb->u.c.nbytes=count;
iocb->u.c.offset=offset;
}
这里注重读写的buf都必需是按扇区对齐的,能够用posix_memalign来分派。
3.猎取完成的IO
longio_getevents(aio_context_tctx_id,longmin_nr,longnr,structio_event*events,structtimespec*timeout);
这里最主要的就是供应一个io_event数组给内核来copy完成的IO哀求到这里,数组的巨细是io_setup时指定的maxevents。
timeout是指守候IO完成的超不时间,设置为NULL暗示一向守候一切到IO的完成。
4.烧毁IO义务
intio_destroy(io_context_tctx);
libaio和epoll的分离
在异步编程中,任何一个环节的堵塞城市招致全部程序的堵塞,以是必定要制止在io_getevents挪用时堵塞式的守候。还记得io_iocb_common中的flags和resfd吗?看看libaio是怎样供应io_getevents和事务轮回的分离:
voidio_set_eventfd(structiocb*iocb,inteventfd)
{
iocb->u.c.flags|=(1<<0)/*IOCB_FLAG_RESFD*/;
iocb->u.c.resfd=eventfd;
}
这里的resfd是经由过程体系挪用eventfd天生的。
inteventfd(unsignedintinitval,intflags);
eventfd是linux2.6.22内核以后加出去的syscall,感化是内核用来关照使用程序产生的事务的数目,从而使使用程序不必频仍地往轮询内核是不是偶然间产生,而是有内核将产生事务的数目写进到该fd,使用程序发明fd可读后,从fd读取该数值,并即刻往内核读取。
有了eventfd,就能够很好地将libaio和epoll事务轮回分离起来:
1.创立一个eventfd
efd=eventfd(0,EFD_NONBLOCK|EFD_CLOEXEC);
2.将eventfd设置到iocb中
io_set_eventfd(iocb,efd);
3.交代AIO哀求
io_submit(ctx,NUM_EVENTS,iocb);
4.创立一个epollfd,并将eventfd加到epoll中
epfd=epoll_create(1);
epoll_ctl(epfd,EPOLL_CTL_ADD,efd,&epevent);
epoll_wait(epfd,&epevent,1,-1);
5.当eventfd可读时,从eventfd读出完成IO哀求的数目,并挪用io_getevents猎取这些IO
read(efd,&finished_aio,sizeof(finished_aio);
r=io_getevents(ctx,1,NUM_EVENTS,events,&tms);
一个完全的编程实例
http://blog.sina.com.cn/s/blog_6b19f21d0100znza.html
以上就是linux异步IO编程的一些基本常识,但愿对感乐趣的同砚或多或少有些协助,感谢。
linux系统的文件布置,etc/,opt/目录的内容等; |
|