天天看点

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 函数

继续阅读