POSIX 提供了函數 lio_listio 可以讓我們一次性發起多個異步 IO 請求。
1. lio_listio
(1) 函數原型
int lio_listio(int mode, struct aiocb *const aiocb_list[], int nitems, struct
(2) 函數參數
- mode
mode 有兩個可選值:LIO_WAIT 和 LIO_NOWAIT.
值 | 含義 |
LIO_WAIT | lio_listio 會阻塞,直到所有的異步 IO 請求完成。此時參數 sevp 被忽略掉 |
LIO_NOWAIT | lio_listio 會立即傳回,當所有異步 IO 請求完成後,會進行異步通知,通知的方式由參數 sevp 指定,該參數可以為 NULL,表示不需要異步通知。通知方式我們在下一講就會說了。 |
- aiocb_list 和 nitems
struct aiocb {
/* 下面所有字段依賴于具體實作 */
int aio_fildes; /* 檔案描述符 */
off_t aio_offset; /* 檔案偏移 */
volatile void *aio_buf; /* 緩沖區位址 */
size_t aio_nbytes; /* 傳輸的資料長度 */
int aio_reqprio; /* 請求優先級 */
struct sigevent aio_sigevent; /* 通知方法 */
int aio_lio_opcode; /* 僅被 lio_listio() 函數使用 */
/* Various implementation-internal fields not shown */
aiocb_list 就是 aiocb 結構體指針的數組,nitems 參數表示數組的大小。在使用 lio_listio 函數時,需要将 aiocb 中的 aio_lio_opcode 成員指派,是以到這裡,我們又學習到了一個新的成員。該成員告訴核心發起的是何中異步 IO 操作。aio_lio_opcode 的值可以為下面這些:
值 | 含義 |
LIO_READ | 發起異步讀操作 |
LIO_WRITE | 發起異步寫操作 |
LIO_NOP | 表示忽略掉該 aiocb |
還有最後一個參數,這裡我們先不考慮它,在使用 lio_listio 函數的時候,将 sevp 設定為 NULL 就行了。
2. 實驗
程式 my_aio_lio 修改了前面的代碼,将 aio_read 函數替換成了 lio_listio 函數發起異步讀請求。程式中并沒有示範同時發起多個請求,隻是發起了一個。實際上,一個你會了,多個也沒什麼問題,無非就是給數組賦幾個值而已。
- 代碼
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <aio.h>
#include <strings.h>
#include <errno.h>
#define ERR_EXIT(msg) do { perror(msg); exit(1); } while(0)
int main() {
int fd, ret;
char buf[64];
struct aiocb my_aiocb;
bzero((char*)&my_aiocb, sizeof(struct aiocb));
my_aiocb.aio_buf = buf;
my_aiocb.aio_fildes = STDIN_FILENO;
my_aiocb.aio_nbytes = 64;
my_aiocb.aio_offset = 0;
// 注意這裡多了一個成員的指派,aio_lio_opcode 成員是專門給 lio_listio 函數用的。
my_aiocb.aio_lio_opcode = LIO_READ;
// 定義一個大小為 5 的數組,多大無所謂了,看你需求了。
struct aiocb* aio_list[5] = { NULL };
// 将你想發起的請求的控制塊放到數組裡,放哪個位置都行。這裡我隻發起了一個讀操作。
aio_list[3] = &my_aiocb;
// 調用 lio_listio 發起讀請求
ret = lio_listio(LIO_NOWAIT, aio_list, 5, NULL);
while(aio_error(&my_aiocb) == EINPROGRESS) {
write(STDOUT_FILENO, ".", 1);
sleep(1);
}
printf("content: %s\n", buf);
return 0;
}
- 編譯和運作
$ gcc my_aio_lio.c -o my_aio_lio -lrt
$ ./my_aio_lio
![](https://img.laitimes.com/img/_0nNw4CM6IyYiwiM6ICdiwiI0gTMx81dsQWZ4lmZf1GLlpXazVmcvwFciV2dsQXYtJ3bm9CX9s2RkBnVHFmb1clWvB3MaVnRtp1XlBXe0xCMy81dvRWYoNHLwEzX5xCMx8FesU2cfdGLwMzX0xiRGZkRGZ0Xy9GbvNGLpZTY1EmMZVDUSFTU4VFRR9Fd4VGdsYTMfVmepNHLrJXYtJXZ0F2dvwVZnFWbp1zczV2YvJHctM3cv1Ce-cmbw5CO0YjN2ATYmdzMhVjYzgDMzYzX2QzNxETM2IzLchDMyIDMy8CXn9Gbi9CXzV2Zh1WavwVbvNmLvR3YxUjLyM3Lc9CX6MHc0RHaiojIsJye.png)
圖1 運作結果
3. 總結
- 掌握 lio_listio 函數