在 libaio 回调中正确处理上下文数据?

Noa*_*ins 3 linux io asynchronous aio

我正在使用内核级异步 I/O(即libaio.h)。struct iocb在提交using之前,io_submit我设置了回调 using io_set_callback,将函数指针粘贴在iocb->data. io_getevents最后,我使用并运行每个回调来获取已完成的事件。

我希望能够在回调中使用一些上下文信息(例如提交时间戳)。我能想到的唯一方法是继续使用io_getevents,但iocb->data指向具有上下文和回调的结构。

是否还有其他方法可以执行类似的操作,并且iocb->data保证在使用时不受影响io_getevents?我的理解是,还有另一种方法可以自动运行回调,如果不指向函数,libaio这将是一个问题。iocb->data

这里的任何澄清都会很好。有关的文档libaio似乎确实缺乏。

Arv*_*vid 5

一种解决方案(我认为是典型的)是从 iocb“派生”,然后将您返回的指针强制转换io_getevents()为结构体。像这样的东西:

struct my_iocb {
    iocb cb;
    void* userdata;
    // ... anything else
};
Run Code Online (Sandbox Code Playgroud)

当您发布作业时,无论一次执行一个还是批量执行,您都会提供一组指向结构的指针,这意味着它们也iocb可能指向。my_iocb

当您从 检索通知时io_getevents(),只需将io_event::obj指针强制转换为您自己的类型:

io_event events[512];
int num_events = io_getevents(ioctx, 1, 512, events, NULL);
for (int i = 0; i < num_events; ++i) {
   my_iocb* job = (my_iocb*)events[i].obj;
   // .. do stuff with job
}
Run Code Online (Sandbox Code Playgroud)

如果您不想阻止 in io_getevents,而是通过文件描述符收到通知(这样您就可以阻止 inselect()epoll(),这可能更方便),我建议使用(未记录的)eventfd集成。

您可以将 an 绑定aiocb到 eventfd 文件描述符io_set_eventfd(iocb* cb, int fd)。每当作业完成时,它就会将 eventfd 加一。

请注意,如果您使用此机制,请务必不要从 io 上下文(使用io_getevents())读取比 eventfd 计数器所说的数量更多的作业,否则在读取 eventfd 计数器并获取作业时会引入竞争条件。