C/C++ Linux 异步IO(AIO)
1.select和poll
IO多路轉換技術, select, poll的原理是: 通過將待監聽文件描述符(fd)加入集合, 然后通過查詢其調用返回值, 取得數據有動靜的fd數量, 再輪詢集合中每個fd, 如果有數據, 就直接讀取; 如果沒有數據, 就等待下一次查詢.
select和poll實現了異步形式通知, 但本質上還是需要主動輪詢.
2. BSD異步IO
System V和BSD都有一套各自的異步IO, 原理類似, 這里只介紹BSD異步IO.
BSD異步IO是信號SIGIO, SIGURG的組合: SIGIO 通用異步IO信號; SIGURG 用來通知進程網絡連接上的帶外數據(data of band, 緊急數據)已經達到.
進程接收SIGIO信號, 需要執行的步驟:
進程接收SIGURG, 只需只需第1,2步. 信號僅對引用支持帶外數據的網絡連接描述符 產生, 如TCP連接(UDP不支持).
BSD異步IO例程
完整源代碼, 請參見?async.c
關鍵步驟代碼
3. POSIX異步IO(AIO)
BSD對不同的設備文件進行異步IO方法不一樣, 如終端設備是產生SIGIO信號, 僅支持帶外數據的設備才能產生SIGURG信號.
POSIX對不同類型文件進行異步IO提供一套一致的方法, SUSv4中, 這些接口被移到了基本部分中, 所以現在所有的平臺都被要求支持這些接口.
3.1 AIO控制塊
異步IO接口使用AIO控制塊來描述IO操作.
AIO控制塊由aiocb結構定義:
字段說明
aio_fildes 表示已打開的文件描述符, 用于讀/寫;
aio_offset 讀寫操作從aio_offset指定的偏移量開始;
aio_buf 用于讀寫操作轉存數據的緩沖區;
aio_nbytes 緩沖區aio_buf的大小;
aio_reqprio 應用程序使用該字段為異步IO請求提示順序. 值必須介于0和sysconf(_SC_AIO_PRIO_DELTA_MAX)返回值之間. 文件同步操作忽略該字段;
aio_lio_opcode 應當進行的操作類型, 只能用于lio_listio (基于列表的異步IO), 值描述見lio_listio章節;
aio_sigevent 指明IO事件完成后, 如何通知應用程序.
sigevent結構:
sigevent字段說明:
-sigev_notify 通知類型, 其取值只能是這3個之一: SIGEV_NONE, SIGEV_SIGNAL, SIGEV_THREAD.
1)SIGEV_NONE 異步IO請求完成后, 不通知進程;
2)SIGEV_SIGNAL 異步IO請求完成后, 產生由sigev_signo字段指定的信號. 也就是說, 需要應用程序捕捉sigev_signo表示的信號, 并在信號處理程序中完成IO數據操作.
3)SIGEV_THREAD 異步IO請求完成時, 調用sigev_notify_function指定的函數, sigev_value作為唯一參數被傳入. 除非sigev_notify_attributes字段被設定為pthread屬性結構的地址, 且該結構指定了一個另外的線程屬性, 否則該函數將在線程分離狀態的一個單獨的線程中執行.
3.2 aio_read & aio_write
使用異步IO前, 應先對AIO控制塊(struct aiocb對象)進行初始化.
aio_read - 異步讀, aio_write - 異步寫:
#include <aio.h>int aio_read(struct aiocb *aiocb);int aio_write(struct aiocb *aiocb);描述
將異步IO請求放入等待處理的隊列中(函數提出請求, 由OS放入). 函數返回值與實際IO操作結果沒有關系. IO操作等待時, 需確保AIO控制塊和數據緩沖區保持穩定, 下面對應的內容也必須始終合法, 不能被釋放, 也不能被復用, 除非IO操作完成.
aio_read是read的異步模擬, aio_write是write的異步模擬.
返回值
成功返回0; 失敗-1
3.3 aio_fsync
aio_fsync - 異步文件同步:
強制所有(等待隊中)等待的異步操作不等待, 而直接寫入持久化的存儲中(通常指磁盤, emmc等), 可以設置一個AIO控制塊并調用aio_fsync.
描述
aiocb->aio_fildes字段(文件描述符)指定異步寫操作被同步的文件.
如果op = O_DSYNC, 那么操作執行像調用fdatasync, 函數立即返回, 但IO操作完成前, 文件數據不會被持久化;
如果op = O_SYNC, 那么操作執行像調用fsync, 函數立即返回, 但IO操作完成前, 文件數據和屬性不會被持久化;
sync, fsync, fdatasync, fflush是什么?
參考sync、fsync、fdatasync、fflush函數區別和使用舉例 | CSDN
| sync | 將所有修改過的(內核)快緩存區排隊進寫隊列, 然后返回, 并不等待實際寫磁盤操作結束 |
| fsync | 只對由fd指定單一文件起作用, 并且等待磁盤操作結束, 然后返回 |
| fdatasync | 類似于fsync, 但只影響文件的數據部分, 不像fsync還會同步更新文件的屬性 |
| fflush | 沖刷IO庫緩存, 將庫緩存內容寫入內核緩沖區 |
3.4 aio_error
aio_error - 獲取異步IO操作(異步讀、寫或同步)的完成狀態
#include <aio.h>int aio_error(const struct aiocb *aiocb);描述
函數返回異步IO請求的錯誤狀態, aiocb指向AIO控制塊, 代表了異步IO請求信息.
返回值
0 異步操作成功, 需要調用aio_return 函數獲取操作返回值;
-1 對aio_error調用失敗, errno被設置;
EINPROGRESS 異步讀、寫或同步操作仍在等待;
其他值 相關異步操作失敗返回的錯誤碼(errno);
3.5 aio_return
aio_error提到, 返回0時表示異步操作成功, 可以調用aio_return獲取操作返回值.
aio_return - 獲取異步IO操作返回值
描述
注意:
返回值
失敗返回-1, errno被設置; 成功時, 返回異步操作結果, 即返回(同步版本)read、write或fsync在被成功調用時可能返回的結果.
3.6 aio_suspend
aio_suspend - 等待異步IO操作完成, 或超時
#include <aio.h>int aio_suspend(const struct aiocb *const list[], int nent, const strct timespec *timeout);描述
執行IO操作時, 如果有其他事務處理而不想被IO操作阻塞, 可以使用異步IO. 如果事務執行完畢后, 還有異步操作尚未完成時, 可調用aio_suspend函數阻止進程, 直到操作完成.
參數
list 指向AIO控制塊數組的指針
nent 表明數組的元素個數
timeout 超時時間
返回值
3種情況:
3.7 aio_cancel
aio_cancel - 取消未完成的異步IO請求
#include <aio.h>int aio_cancel(int fd, struct aiocb *aiocb);描述
如果不想完成還在等待中的異步IO操作時, 可以調用aio_cancel嘗試取消. 描述為嘗試, 是因為系統無法保證一定能取消正在進行的任何操作.
如果異步IO操作成功取消, 相應AIO控制塊調用aio_error將返回錯誤ECANCELED; 如果操作不能被取消, 那么相應的AIO控制塊不會被修改
參數
fd 指定未完成的異步IO操作的文件描述符
aiocb 如果aiocb = NULL, 系統會嘗試取消所有該文件上未完成的異步IO操作; 其他情況, 系統將嘗試取消aiocb指向的單個AIO控制塊描述的單個異步IO操作.
返回值
4個值之一:
AIO_ALLDONE 所有操作在嘗試取消前, 已經完成;
AIO_CANCELED 所有要求的操作已被取消;
AIO_NOTCANCELED 至少有一個要求的操作沒有被取消;
-1 對aio_cancel調用失敗, 設置errno;
3.8 lio_listio
lio_listio - 初始化io請求列表
#include <aio.h>int lio_listio(int mode, struct aiocb *const aiocb_list[], int nitems, struct sigevent *sevp);描述
既能以同步方式使用, 也能以異步的方式使用. 函數提交一系列由一個AIO控制塊列表描述的IO請求.
每個AIO控制塊中, aio_lio_opcode字段指定了該操作是一個讀操作(LIO_READ), 寫操作(LIO_WRITE), 還是將忽略的空操作(LIO_NOP). 讀操作, 會按照對應的AIO控制塊被傳給aio_read來處理; 寫操作, 會被傳給aio_write處理.
參數
mode 決定IO釋放真的是異步的. 取值說明:
aiocb_list 指向AIO控制塊列表, 指定了要運行的IO操作.
nitems 指定了aiocb_list數組元素格式.
實現限制
實現一般會限制一些參數的實際取值
POSIX.1中異步IO運行時不變量的值
| AIO_LISTIO_MAX | 單個列表IO調用中的最大IO操作數 | _POSIX_AOI_LISTIO_MAX |
| AIO_MAX | 未完成的異步IO操作的最大數目 | _POSIX_AIO_MAX |
| AIO_PRIO_DELTA_MAX | 進程可以減少的異步IO優先級的最大值 | 0 |
4. AIO的使用例程
以從一個文件讀取數據, 然后寫到另外一個文件為例.
4.1 同步IO操作
流程
4.2 異步IO操作 (AIO)
流程
?
更多C/C++Linux后臺開發架構體系學習文章請關注筆者:
Linux后臺開發獅?www.zhihu.com/people/linux-9-85正在上傳…重新上傳取消
筆者會不斷更新C/C++Linux后臺開發架構體系,程序員面試經驗以及答題答案總結分享;敬請關注更新。
總結
以上是生活随笔為你收集整理的C/C++ Linux 异步IO(AIO)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: DB2远程链接数据库编目命令代码
- 下一篇: swagger 使用指南