天天看點

126-POSIX 異步IO(批量請求)

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      
126-POSIX 異步IO(批量請求)

圖1 運作結果

3. 總結

  • 掌握 lio_listio 函數

繼續閱讀