You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

LibAio技术疑问:未调用io_getevents为何仍能读取到数据?

LibAio 使用疑问解答:未调用 io_getevents 却读取到数据的原因及规范用法

1. 调用 io_submit 方法后,是否必须调用 io_getevents 方法?

是,必须调用。io_submit 仅负责将IO请求提交到内核队列,不会等待IO操作完成,也不会同步返回操作结果。如果不调用 io_getevents,内核中对应的IO上下文资源无法被正确回收,会造成资源泄漏;同时你无法确认IO请求是否真的完成、是否成功,程序行为会处于未定义状态。

2. 若必须调用,为何会出现未调用却成功获取数据的情况?

这是内核同步完成优化导致的巧合:

  • 当读取的文件很小,或者文件内容已被操作系统缓存到内存中时,内核会直接在 io_submit 调用过程中完成数据拷贝,不需要异步等待磁盘IO。
  • 这种行为完全依赖系统状态(缓存情况、文件大小、内核调度策略),属于不可预期的“副作用”,绝对不能作为正常逻辑依赖。如果读取大文件或缓存未命中的文件,double_check_m_buf 中不会有有效数据,甚至程序会崩溃或出现乱码。

3. 何时调用 io_getevents 获取读取结果?能否多次调用该方法?

  • 调用时机:提交IO请求后,当你需要获取IO操作的结果(成功/失败状态、实际读取字节数),或者需要等待IO完成再继续后续逻辑时,调用 io_getevents。通常会在 io_submit 后,通过循环调用 io_getevents 等待所有提交的请求完成。
  • 是否可多次调用:完全可以。io_getevents 每次调用可以获取一批已完成的IO事件,你可以根据返回的完成事件数,循环调用直到所有提交的请求都被处理完毕。

修正后的演示代码(添加 io_getevents 调用)

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

#define error() printf("error [%s : %d]\n", __FILE__, __LINE__)

#define BUFF_SIZE 51
#define BUFF_CNT 50
#define READLEN 4194304

int main(int argc, char *argv[])
{
    int fd = open(__FILE__, O_RDONLY);
    if (fd == -1) {
        error();
        return -1;
    }

    io_context_t ctx = 0;
    int err = io_setup(BUFF_CNT, &ctx);
    if (err != 0) {
        error();
        return -1;
    }

    struct iocb *io = (struct iocb *)malloc(sizeof(struct iocb));
    if (NULL == io) {
        printf("alloc struct iocb failed");
        return -1;
    }
    memset(io, 0x00, sizeof(struct iocb)); // 修正原代码错误:sizeof(io)是指针大小,改为结构体实际大小

    char double_check_m_buf[READLEN];
    memset(double_check_m_buf, 0, READLEN); // 初始化缓冲区,避免脏数据干扰
    io_prep_pread(io, fd, double_check_m_buf, READLEN, 0);

    int rc = io_submit(ctx, 1, &io);
    if (rc < 0) {
        printf("aio send read one block failed");
        return -1;
    }

    // 调用io_getevents等待IO完成
    struct io_event events[1];
    int ret = io_getevents(ctx, 1, 1, events, NULL);
    if (ret > 0) {
        // 检查IO是否成功
        if (events[0].res > 0) {
            printf("aio read completed, actual read len: %ld \n content: %.*s", 
                   events[0].res, (int)events[0].res, double_check_m_buf);
        } else {
            printf("aio read failed, error code: %ld\n", events[0].res);
        }
    } else {
        printf("io_getevents failed\n");
    }

    // 清理资源
    io_destroy(ctx);
    free(io);
    close(fd);

    return 0;
}

注意:原演示代码存在一处错误:memset(io, 0x00, sizeof(io)) 中 sizeof(io) 是指针的大小(通常8字节),而非 struct iocb 的实际大小,会导致结构体未完全初始化,修正后改为 sizeof(struct iocb)。

内容的提问来源于stack exchange,提问作者hui li

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.01 11:15:38