linux libaio介绍

article/2025/11/6 10:22:16

Linux的I/O机制经历了一下几个阶段的演进:
1. 同步阻塞I/O: 用户进程进行I/O操作,一直阻塞到I/O操作完成为止。
2. 同步非阻塞I/O: 用户程序可以通过设置文件描述符的属性O_NONBLOCK,I/O操作可以立即返回,但是并不保证I/O操作成功。
3. 异步事件阻塞I/O: 用户进程可以对I/O事件进行阻塞,但是I/O操作并不阻塞。通过select/poll/epoll等函数调用来达到此目的。
4. 异步时间非阻塞I/O: 也叫做异步I/O(AIO),用户程序可以通过向内核发出I/O请求命令,不用等带I/O事件真正发生,可以继续做另外的事情,等I/O操作完成,内核会通过函数回调或者信号机制通知用户进程。这样很大程度提高了系统吞吐量。

图 1 给出了同步和异步模型,以及阻塞和非阻塞的模型。

图 1. 基本 Linux I/O 模型的简单矩阵
 linux下有aio封装,aio_*系列的调用是glibc提供的,是glibc用线程+阻塞调用来模拟的,性能很差,为了能更多的控制io行为,可以使用更为低级libaio。

libaio项目: http://oss.oracle.com/projects/libaio-oracle/

libaio的使用并不复杂,过程为:libaio的初始化,io请求的下发和回收,libaio销毁

一、libaio接口
libaio提供下面五个主要API函数:

int io_setup(int maxevents, io_context_t *ctxp);
int io_destroy(io_context_t ctx);
int io_submit(io_context_t ctx, long nr, struct iocb *ios[]);
int io_cancel(io_context_t ctx, struct iocb *iocb, struct io_event *evt);
int io_getevents(io_context_t ctx_id, long min_nr, long nr, struct io_event *events, struct timespec *timeout);

五个宏定义:

void io_set_callback(struct iocb *iocb, io_callback_t cb);
void io_prep_pwrite(struct iocb *iocb, int fd, void *buf, size_t count, long long offset);
void io_prep_pread(struct iocb *iocb, int fd, void *buf, size_t count, long long offset);
void io_prep_pwritev(struct iocb *iocb, int fd, const struct iovec *iov, int iovcnt, long long offset);
void io_prep_preadv(struct iocb *iocb, int fd, const struct iovec *iov, int iovcnt, long long offset);

这五个宏定义都是操作struct iocb的结构体。struct iocb是libaio中很重要的一个结构体,用于表示IO,但是其结构略显复杂,为了保持封装性不建议直接操作其元素而用上面五个宏定义操作。

二、libaio的初始化和销毁

观察libaio五个主要API,都用到类型为io_context的变量,这个变量为libaio的工作空间。不用具体去了解这个变量的结构,只需要了解其相关操作。创建和销毁libaio分别用到io_setup(也可以用io_queue_init,区别只是名字不一样而已)和io_destroy。

int io_setup(int maxevents, io_context_t *ctxp);

这里也需要open需要操作的文件,注意设置O_DIRECT标志
int io_destroy(io_context_t ctx);
三、libaio读写请求的下发和回收
1. 请求下发

libaio的读写请求都用io_submit下发。下发前通过io_prep_pwrite和io_prep_pread生成iocb的结构体,做为io_submit的参数。这个结构体中指定了读写类型、起始扇区、长度和设备标志符。

libaio的初始化不是针对一个具体设备进行初始,而是创建一个libaio的工作环境。读写请求下发到哪个设备是通过open函数打开的设备标志符指定。

 

2. 请求返回
读写请求下发之后,使用io_getevents函数等待io结束信号:

int io_getevents(io_context_t ctx_id, long min_nr, long nr, struct io_event *events, struct timespec *timeout);

io_getevents返回events的数组,其参数events为数组首地址,nr为数组长度(即最大返回的event数),min_nr为最少返回的events数。timeout可填NULL表示无等待超时。io_event结构体的声明为:

struct io_event {
    PADDEDptr(void *data, __pad1);
    PADDEDptr(struct iocb *obj,  __pad2);
    PADDEDul(res,  __pad3);
    PADDEDul(res2, __pad4);
};

其中,res为实际完成的字节数;res2为读写成功状态,0表示成功;

obj为之前下发的struct iocb结构体。这里有必要了解一下struct iocb这个结构体的主要内容:
iocbp->iocb.u.c.nbytes 字节数
iocbp->iocb.u.c.offset 偏移
iocbp->iocb.u.c.buf 缓冲空间
iocbp->iocb.u.c.flags 读写

 

3. 自定义字段
struct iocb除了自带的元素外,还留有供用户自定义的元素,包括回调函数和void *的data指针。如果在请求下发前用io_set_callback绑定用户自定义的回调函数,那么请求返回后就可以显示的调用该函数。回调函数的类型为:

void callback_function(io_context_t ctx, struct iocb *iocb, long res, long res2);

另外,还可以通过iocbp->data指针挂上用户自己的数据。

注意:实际使用中发现回调函数和data指针不能同时用,可能回调函数本身就是使用的data指针

#include <stdlib.h>
#include <stdio.h>
#include <libaio.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <libaio.h>


int srcfd=-1;
int odsfd=-1;


#define AIO_BLKSIZE  1024
#define AIO_MAXIO 64


static void wr_done(io_context_t ctx, struct iocb *iocb, long res, long res2)
{
       if(res2 != 0)
       {
              printf("aio write error\n");
       }
       if(res != iocb->u.c.nbytes)
       {
              printf( "write missed bytes expect %d got %d\n", iocb->u.c.nbytes, res);
              exit(1);
       }
 
       free(iocb->u.c.buf);
       free(iocb);
}


static void rd_done(io_context_t ctx, struct iocb *iocb, long res, long res2)
{
       /*library needs accessors to look at iocb*/
       int iosize = iocb->u.c.nbytes;
       char *buf = (char *)iocb->u.c.buf;
       off_t offset = iocb->u.c.offset;
       int  tmp;
       char *wrbuff = NULL;
 
       if(res2 != 0)
       {
             printf("aio read\n");
       }
       if(res != iosize)
       {
              printf( "read missing bytes expect %d got %d", iocb->u.c.nbytes, res);
              exit(1);
       }
 
       /*turn read into write*/
       tmp = posix_memalign((void **)&wrbuff, getpagesize(), AIO_BLKSIZE);
       if(tmp < 0)
       {
              printf("posix_memalign222\n");
              exit(1);
       }
 
       snprintf(wrbuff, iosize + 1, "%s", buf);
 
       printf("wrbuff-len = %d:%s\n", strlen(wrbuff), wrbuff);
       printf("wrbuff_len = %d\n", strlen(wrbuff));
       free(buf);
       
       io_prep_pwrite(iocb, odsfd, wrbuff, iosize, offset);
       io_set_callback(iocb, wr_done);
       
       if(1!= (res=io_submit(ctx, 1, &iocb)))
              printf("io_submit write error\n");
       
       printf("\nsubmit  %d  write request\n", res);
}


void main(int args,void * argv[])
{
    int length = sizeof("abcdefg");
    char * content = (char * )malloc(length);
    io_context_t myctx;
    int rc;
    char * buff=NULL;
    int offset=0;
    int num,i,tmp;
    
    if(args<3)
    {
        printf("the number of param is wrong\n");
        exit(1);
    }


      if((srcfd=open(argv[1],O_RDWR))<0)
      {
        printf("open srcfile error\n");
        exit(1);
      }


      printf("srcfd=%d\n",srcfd);


      lseek(srcfd,0,SEEK_SET);
      write(srcfd,"abcdefg",length);
      
      lseek(srcfd,0,SEEK_SET);
      read(srcfd,content,length);


      printf("write in the srcfile successful,content is %s\n",content);


      if((odsfd=open(argv[2],O_RDWR))<0)
      {
        close(srcfd);
        printf("open odsfile error\n");
        exit(1);
      }


    memset(&myctx, 0, sizeof(myctx));
    io_queue_init(AIO_MAXIO, &myctx);
 
     
       struct iocb *io = (struct iocb*)malloc(sizeof(struct iocb));
       int iosize = AIO_BLKSIZE;
       tmp = posix_memalign((void **)&buff, getpagesize(), AIO_BLKSIZE);
        if(tmp < 0)
        {
              printf("posix_memalign error\n");
              exit(1);
         }
        if(NULL == io)
        {
            printf( "io out of memeory\n");
             exit(1);
        }


                           
        io_prep_pread(io, srcfd, buff, iosize, offset);
                      
        io_set_callback(io, rd_done);
                
         printf("START鈥n\n");
                
         rc = io_submit(myctx, 1, &io);
    
          if(rc < 0)
               printf("io_submit read error\n");
          
          printf("\nsubmit  %d  read request\n", rc);
             
           
          //m_io_queue_run(myctx);
          
       struct io_event events[AIO_MAXIO];
          io_callback_t cb;
         
          num = io_getevents(myctx, 1, AIO_MAXIO, events, NULL);
          printf("\n%d io_request completed\n\n", num);
      
          for(i=0;i<num;i++)
         {
              cb = (io_callback_t)events[i].data;
              struct iocb *io = events[i].obj;
            
              printf("events[%d].data = %x, res = %d, res2 = %d\n", i, cb, events[i].res, events[i].res2);
              cb(myctx, io, events[i].res, events[i].res2);
          }
}

 

 

 


http://chatgpt.dhexx.cn/article/8gxbjPKf.shtml

相关文章

Linux开发之libaio源码分析及应用

1. 简介 Linux的POSIX API由glibc提供&#xff0c;2000年年之前&#xff0c;glibc一直没有提供异步I/O的调用API。Red Hat公司基于Linux内核的符号表封装了一套异步I/O(简称aio)的接口&#xff0c;并提供了一些新的接口用来简化上下文配置&#xff0c;开成一个库&#xff0c;命…

HC-SR501人体红外感应电子模块

1&#xff09;理解两种触发方式&#xff1a;可重复触发和不可重复触发 2&#xff09;学会调节两个属性&#xff1a;延迟调节和灵敏度调节 &#xff08;在不同触发方式下&#xff0c;大家要自己调自己的设备&#xff0c;不同延迟反应快速性不同&#xff0c;不同灵敏度感应的范围…

人体红外传感器简明教程

学习物联网&#xff0c;来HaaSEDU就对了 人体红外热释电运动传感器 一、产品简介 热释电红外运动传感器能检测运动的人或动物身上发出的红外线&#xff0c;输出开关信号&#xff0c;可以应用于各种需要检测运动人体的场合。传统的热释电红外传感器需要人体热释电红外探头、专…

基于STM32F0实现人体红外传感器

​​​​​​目的 了解人体红外传感器 HC-SR501 的驱动原理和STM32F030的中断机制&#xff0c;通过配置 STM32F030 芯片 GPIO 相关寄存器和外部触发中断实现人体红外传感器检测人体。 原理 中断是指当CPU执行程序时&#xff0c;由于发生了某种随机的事件&#xff08;外部或内…

Arduino Uno 使用 人体红外传感器(HC_SR051)实现 人体感应灯

“登”&#xff0c;亮了.&#xff0c; 每当我游走在图书馆书架之间就会有这样的一个情景。 这次实验使用的模块是人体红外传感器&#xff08;HC_SR051&#xff09;&#xff0c;配上Arduino Uno 实现人体感应灯的实现。 先看看这模块&#xff08;点击查看大图&#xff09; 实验效…

HC-SR501 人体红外感应模块 单片机

https://blog.csdn.net/zy19981110/article/details/89947118?ops_request_misc%257B%2522request%255Fid%2522%253A%2522161616067916780357245177%2522%252C%2522scm%2522%253A%252220140713.130102334…%2522%257D&request_id161616067916780357245177&biz_id0&…

HC-SR501人体红外传感器

了解人体红外传感器HC-SR501的驱动原理&#xff0c;通过配置STM32F030芯片GPIO相关寄存器&#xff0c;让人体红外传感器识别到人体时使蜂鸣器响起的基础实验。 1、HC-SR501是基于红外线HC-SR501是基于红外线技术的自动控制模块 &#xff0c;采用德国原装进口LHI778 探头设计&a…

基于STM32的红外人体感应器控制LED灯的状态

文章目录 一、红外人体感应器的介绍二、利用红外人体感应器实现控制LED灯三、总结 一、红外人体感应器的介绍 产品参数 产品特点 ①全自动感应 当人进入其感应范围则输出高电平&#xff0c;人离开感应范围则自动延时关闭高电平&#xff0c;输出低电平。 ②光敏控制 (可选&…

人体红外线传感器

基于Arduino的人体红外线传感器 目的: 1.红外线模组与arduino结合&#xff0c;利用当有人进入感应范围内则输入高电平&#xff0c;人离开感应范围则自动关闭高电平&#xff0c;输出低电平的原理&#xff0c;采集到人身体上的红外信号&#xff0c;显示于 PC 串行端口监控窗口和…

人体红外传感器HC-SR501特点及使用介绍

人体红外传感器HC-SR501特点及使用介绍 前言一、人体红外传感器外观二、示意图三、相关参数讲解1.引脚2.优点3.产品特性&#xff08;根据官方参考资料&#xff09; 四、适用场所范围总结 前言 本文着重介绍人体红外传感器HC-SR501(基于红外线技术的自动控制模块)的原理、功能及…

【HC-SR501人体红外传感器】

HC-SR501人体红外传感器 今天分享的是HC-SR501人体红外传感器的使用&#xff0c;下面我会结合stm32以及正在做的合泰HT32这两个型号的芯片进行例程讲解。 HC-SR501介绍 1、HC-SR501是基于红外线HC-SR501是基于红外线技术的自动控制模块 &#xff0c;采用德国原装进口LHI778 探头…

微信小程序点击数据列表,进入列表详情页面的思路

1.在index.wxml 通过 bindtap去绑定一个事件。 对于详情页的传输数据&#xff0c;点击事件可以通过 data- 去实现&#xff0c;后面相当于是键值对&#xff0c;data-id"{{item.id}}"&#xff0c;意思是把列表的id传过去。 <view class"goods"><vi…

小程序---小程序列表项拖拽排序

一、拖拽效果图展示 首先&#xff0c;上个gif图看看效果 吐血测试了一天&#xff0c;目前还未发现bug。ps(拖拽效果仅在前端实现&#xff0c;未和后端交互) 文章代码参考小程序实现列表拖拽排序 &#xff0c;参考文章还是存在一些bug和不足&#xff0c;比如&#xff0c;样式代…

微信小程序列表页

我们在做Android开发时,几乎每个app都有几个列表,在Android中列表一般是用listview&#xff0c;后来就使用recyclerview做了,不管是小程序还是Android或者ios&#xff0c;列表都是常见的一种数据展示方式,那么在小程序中怎么实现呢&#xff1f;先使用最笨的方法做, 如图&#…

小程序列表展示

小程序列表展示 wxml代码 <view class"content"><form catchsubmit"formSuos" catchreset"formReset"><view class"group"><view class"sous"><input class"text1_3" auto-focus pl…

微信小程序信息展示列表

微信小程序信息展示列表 效果展示: 代码展示: wxml <view class"head"><view class"head_item">分类</view><view class"ring"></view><view class"head_item">价格</view> </view>…

微信小程序-列表展示、条目点击。

直接贴图&#xff1a; wx:for"{{datas}}"设置数据源&#xff1b; wx:for-item"item"设置条目名称&#xff1b; data-index{{index}}设置角标。 bindtapitemClick点击事件。 {{item.item}}显示数据 datas数据源。 条目点击 itemClick: function(e) { …

【微信小程序】-- 案例 - 本地生活(列表页面)(三十)

&#x1f48c; 所属专栏&#xff1a;【微信小程序开发教程】 &#x1f600; 作  者&#xff1a;我是夜阑的狗&#x1f436; &#x1f680; 个人简介&#xff1a;一个正在努力学技术的CV工程师&#xff0c;专注基础和实战分享 &#xff0c;欢迎咨询&#xff01; &…

微信小程序删除list指定列表项

一、删除效果展示&#xff1a; // 重要代码片段async deleteListItem(e) {const sureResult await wx.showModal({title: "提示",content: "确定要删除这项吗",});if (sureResult.confirm) {const { index } e.currentTarget.dataset;setTimeout(()>{…

【小程序从0到1】小程序常用组件一览

欢迎来到我的博客 &#x1f4d4;博主是一名大学在读本科生&#xff0c;主要学习方向是前端。 &#x1f36d;目前已经更新了【Vue】、【React–从基础到实战】、【TypeScript】等等系列专栏 &#x1f6e0;目前正在学习的是&#x1f525; R e a c t / 小程序 React/小程序 React/…