libaio學習

      網友投稿 3390 2025-04-01

      libaio是linux版本的aio庫,aio指的是異步io。這里記錄下libaio的使用,主要過程為:libaio的初始化,io請求的下發和回收,libaio銷毀。

      libaio的接口

      libaio的初始化

      int io_setup(int maxevents, io_context_t *ctxp); // maxevents表示能處理的最大事件數,同時初始化結構io_context_t,調用之前ctxp的內容必須初始化為0

      提交IO讀寫請求

      long io_submit (io_context_t ctx_id, long nr, struct iocb **iocbpp); // 提交任務前,必須先填充iocb結構體。可以使用io_prep_pwrite和io_prep_pread接口生成iocb的結構體,這其中涉及到fd,需要先open對應的文件,并設置為O_DIRECT標志。另外,buff需要先對齊。 struct io_iocb_common { PADDEDptr(void *buf, __pad1); // 緩存空間 PADDEDul(nbytes, __pad2); // 字節數 long long offset; // 偏移 long long __pad3; unsigned flags; unsigned resfd; }; /* result code is the amount read or -'ve errno */ struct iocb { PADDEDptr(void *data, __pad1); /* Return in the io completion event */ 用戶回調函數,可以通過io_set_callback設置 PADDED(unsigned key, __pad2); /* For use in identifying io requests */ short aio_lio_opcode; short aio_reqprio; int aio_fildes; union { struct io_iocb_common c; struct io_iocb_vector v; struct io_iocb_poll poll; struct io_iocb_sockaddr saddr; } u; }; void io_prep_pread(struct iocb *iocb, int fd, void *buf, size_t count, long long offset) { 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; } void io_prep_pwrite(struct iocb *iocb, int fd, void *buf, size_t count, long long offset) { 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必須是按照扇區對齊的(512的倍數),可以使用posix_memalign進行對齊。

      (1)為什么是O_DIRECT標志

      O_DIRECT標志指采用DIRECT I/O,相對于此,有個Buffered I/O。后者需要將用戶空間的數據拷貝到內核緩存區,然后再拷貝到磁盤,這操作造成了CPU資源和內存資源的浪費。而DIRECT I/O,不需要通過內核緩存數據,直接將用戶空間數據拷貝到磁盤。所以選擇O_DIRECT標志,利于減少內存拷貝和CPU利用率。但是這樣做的話,需要用戶保證內存對齊,否則數據是無法正常寫入的,可以使用posix_memalign進行內存對齊。讀寫緩沖區的地址、內容的大小、文件偏移必須是扇區的倍數(通常是512字節)。

      (2)posix_memalign的使用

      #include int posix_memalign (void **memptr, size_t alignment, size_t size);

      如果調用posix_memalign()成功時,會返回size字節的動態內存,并且這塊內存的地址是alignment的倍數。參數alignment必須是2的冪,還是void指針的大小的倍數。返回的內存塊的地址放在了memptr里面,函數返回值是0。

      如果調用失敗時,沒有內存會被分配,memptr的值沒有被定義,返回如下錯誤碼之一:

      EINVAL:參數不是2的冪,或者不是void指針的倍數。

      ENOMEM:沒有足夠的內存去滿足函數的請求。

      要注意的是,對于這個函數,errno不會被設置,只能通過返回值得到。

      由posix_memalign()獲得的內存通過free( )釋放。

      IO請求返回

      讀寫io請求下發后,使用io_getevents函數等待io結束信號。

      libaio學習

      int io_getevents(io_context_t ctx_id, long min_nr, long nr, struct io_event *events, struct timespec *timeout); // 返回events數組,events為數組首地址; // nr為數組長度,即最大返回的event數; // min_nr為最少返回的event數; // timieout表示超時時間,填寫NULL表示無等待超時 // io_event的結構體內容: struct io_event {undefined PADDEDptr(void *data, __pad1); PADDEDptr(struct iocb *obj, __pad2); PADDEDul(res, __pad3); PADDEDul(res2, __pad4); }; // res為實際完成的字節數 // res2位讀寫成功的狀態,0表示成功 // obj為io_submit中下發的內容

      IO取消或者銷毀

      int io_destroy(io_context_t ctx); // 跟io_setup對應 int io_cancel(io_context_t ctx, struct iocb *iocb, struct io_event *evt); // 取消之前通過io_submit傳入的iocb

      實例

      單獨使用aio

      #include #include #include #include #include #include int aio_write(void *buff, struct iocb* p) { strcpy(buff, "hello world"); int fd = open("./aiotest.txt", O_WRONLY | O_CREAT | O_APPEND | O_DIRECT, 0644); io_prep_pwrite(p, fd, buff, 1024, 0); return fd; } int aio_read(void *buff, struct iocb* p) { int fd = open("./aiotest.txt", O_RDONLY | O_CREAT | O_APPEND | O_DIRECT, 0644); io_prep_pread(p, fd, buff, 1024, 0); return fd; } int main() { io_context_t ctx; memset(&ctx, 0, sizeof(ctx)); int ret = io_setup(10, &ctx); if (ret != 0) { printf("io_setup fail: errno=%d, ret=%d\n", errno, ret);// 注意,errno并沒有記錄相關的錯誤 return -1; } struct iocb iocbpp; struct iocb *p = &iocbpp; void *buff = NULL; posix_memalign(&buff, 512, 1024); int fd = aio_read(buff, p); // aio_write(buff, p); ret = io_submit(ctx, 1, &p); if (ret != 1) { io_destroy(ctx); free(buff); printf("io_submit fail, errno=%d, ret=%d\n", errno, ret); return -1; } struct io_event events[10]; if (io_getevents(ctx, 1, 10, events, NULL) != 1) { printf("io_getevents fail\n"); close(fd); io_destroy(ctx); free(buff); return -1; } printf("read result: %s\n", events[0].obj->u.c.buf); printf("read res: %s\n", buff); close(fd); io_destroy(ctx); free(buff); return 0; }

      aio和epoll結合

      需要使用到io_set_eventfd,將evenfd寫到iocb中,io_set_eventfd的定義如下:

      void io_set_eventfd(struct iocb *iocb, int eventfd) { iocb->u.c.flags |= (1 << 0) /* IOCB_FLAG_RESFD */; iocb->u.c.resfd = eventfd; }

      具體步驟:

      (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);

      具體實例:

      // aio.cpp #include #include #include #include #include #include #include #include int aio_write(void *buff, struct iocb* p) { strcpy((char*)buff, "hello world"); int fd = open("./aiotest.txt", O_WRONLY | O_CREAT | O_APPEND | O_DIRECT, 0644); io_prep_pwrite(p, fd, buff, 1024, 0); return fd; } int aio_read(void *buff, struct iocb* p) { int fd = open("./aiotest.txt", O_RDONLY | O_CREAT | O_APPEND | O_DIRECT, 0644); io_prep_pread(p, fd, buff, 1024, 0); return fd; } int main() { io_context_t ctx; memset(&ctx, 0, sizeof(ctx)); int ret = io_setup(10, &ctx); if (ret != 0) { printf("io_setup fail: errno=%d, ret=%d\n", errno, ret); return -1; } struct iocb iocbpp; struct iocb *p = &iocbpp; void *buff = NULL; posix_memalign(&buff, 512, 1024); int fd = aio_read(buff, p); // aio_write(buff, p); int efd = eventfd(0, EFD_NONBLOCK | EFD_CLOEXEC); io_set_eventfd(p, efd); ret = io_submit(ctx, 1, &p); if (ret != 1) { io_destroy(ctx); free(buff); printf("io_submit fail, errno=%d, ret=%d\n", errno, ret); return -1; } int epfd = epoll_create(1); struct epoll_event event; event.events = EPOLLET | EPOLLIN; event.data.fd = efd; epoll_ctl(epfd, EPOLL_CTL_ADD, efd, &event); uint64_t data; while(true) { ret = epoll_wait(epfd, &event, 1, -1); if (ret > 0) { ret = read(efd, &data, sizeof(data)); // 這里會阻塞 if (ret < 0) { printf("read fail\n"); } printf("success read from efd, read %d bytes, data is %d\n", ret, data); struct io_event events[10]; if (io_getevents(ctx, 1, 10, events, NULL) != 1) { printf("io_getevents fail\n"); close(fd); io_destroy(ctx); free(buff); return -1; } printf("read result: %s\n", events[0].obj->u.c.buf); } else if (ret == 0) { printf("epoll wait timeout\n"); break; } else { printf("epoll wait error\n"); break; } } close(fd); io_destroy(ctx); free(buff); return 0; }

      參考:

      https://blog.csdn.net/enlaihe/article/details/112320114?spm=1001.2014.3001.5506

      https://blog.csdn.net/cjsycyl/article/details/9332241 (epoll和aio結合)

      https://zhuanlan.zhihu.com/p/145394613?from_voters_page=true (講得挺清楚)

      https://blog.csdn.net/brucexu1978/article/details/7085924

      Linux

      版權聲明:本文內容由網絡用戶投稿,版權歸原作者所有,本站不擁有其著作權,亦不承擔相應法律責任。如果您發現本站中有涉嫌抄襲或描述失實的內容,請聯系我們jiasou666@gmail.com 處理,核實后本網站將在24小時內刪除侵權內容。

      版權聲明:本文內容由網絡用戶投稿,版權歸原作者所有,本站不擁有其著作權,亦不承擔相應法律責任。如果您發現本站中有涉嫌抄襲或描述失實的內容,請聯系我們jiasou666@gmail.com 處理,核實后本網站將在24小時內刪除侵權內容。

      上一篇:無代碼開發軟件(無代碼開發是什么)
      下一篇:Google Play】App Bundle 使用詳解 ( 簡介 | 應用內更新 | 即時更新 | 靈活更新 )
      相關文章
      亚洲AV成人精品日韩一区| 亚洲sss综合天堂久久久| 亚洲偷偷自拍高清| 亚洲大片免费观看| 亚洲av无码乱码国产精品| 亚洲乳大丰满中文字幕| 国产亚洲成人久久| 亚洲中文字幕无码不卡电影| 久久综合亚洲色HEZYO国产| 国产精品亚洲美女久久久| 精品国产人成亚洲区| 久久久久亚洲av毛片大| 久久久久亚洲av毛片大| 亚洲精品亚洲人成在线观看| 亚洲精品无码mv在线观看网站| 亚洲乱码日产一区三区| 亚洲av永久无码制服河南实里| 亚洲大成色www永久网站| 亚洲精品免费在线观看| 久久亚洲精品中文字幕| 亚洲男女一区二区三区| 亚洲一区中文字幕在线观看| 成人亚洲国产va天堂| 亚洲Av永久无码精品黑人| 国产精品亚洲片在线花蝴蝶| 亚洲国产人成中文幕一级二级| 国产精品亚洲mnbav网站| 亚洲国产精品VA在线观看麻豆| 久久精品国产亚洲av麻| 亚洲无砖砖区免费| 亚洲字幕AV一区二区三区四区| 亚洲AV无码一区二区三区电影 | 亚洲av日韩av天堂影片精品| 亚洲精品国产手机| 亚洲AV成人影视在线观看 | 久热综合在线亚洲精品| 91精品国产亚洲爽啪在线影院| 亚洲欧洲尹人香蕉综合| 亚洲愉拍一区二区三区| 亚洲AⅤ优女AV综合久久久| 国产成人亚洲综合|