POSIX AIO库和回调处理程序

时间:2009-08-02 21:26:48

标签: linux posix aio

根据aio_read / write上的文档,AIO库基本上有两种方式可以通知您的应用程序异步文件I / O操作已完成。 1)您可以使用信号,2)您可以使用回调函数

我认为回调函数比信号更受欢迎,并且可能更容易集成到更高级别的多线程库中。不幸的是,至少可以说这个功能的文档很乱。某些源(例如man page for the sigevent struct)表示您需要将sigevent结构中的sigev_notify数据成员设置为SIGEV_CALLBACK,然后提供函数处理程序。据推测,处理程序在同一个线程中调用。其他documentation表示你需要将sigev_notify设置为SIGEV_THREAD,它将在新创建的线程中调用回调处理程序。

无论如何,在我的Linux系统(带有2.6.28内核的Ubuntu)上,SIGEV_CALLBACK似乎没有在任何地方定义,但SIGEV_THREAD的工作方式与宣传的一样。不幸的是,创建一个新线程来调用回调处理程序似乎效率很低,特别是如果你需要调用许多处理程序。最好使用现有的线程池,类似于大多数网络I / O事件多路分解器的工作方式。某些版本的UNIX(如QNX)包含一个SIGEV_SIGNAL_THREAD标志,它允许您使用指定的现有线程调用处理程序,但这似乎在Linux上不可用,它似乎甚至不是POSIX的一部分标准。

那么,是否可以以在预先分配的后台线程/线程池中调用用户处理程序的方式使用POSIX AIO库,而不是每次调用处理程序时创建/销毁新线程?

4 个答案:

答案 0 :(得分:2)

我通常发现通过在专用后台线程或线程中执行普通IO来模拟异步IO更简单,更便携,以我喜欢的方式调度完成回调。

答案 1 :(得分:1)

一种方法是使用SIGEV_SIGNALrealtime signal将“就绪文件描述符”“携带”到信号处理程序。实时信号队列和信号处理程序在一个线程中异步执行,因此这种方法在功能上或多或少等同于SIGEV_CALLBACK

/*
 * Warning!  Untested!
 * Also, safe initialization, per-thread signal masking and
 * error-checking omitted.
 */

static void my_callback(int sig, siginfo_t *info, void *context) {
  int fd;

  fd = info->si_value.sival_int;
  /* ...enqueue the fd for processing... */
}

struct sigaction sa;

sa.sa_handler = my_callback;                 /* Register our async callback */
sa.sa_flags = SA_SIGINFO;
sigaction(SIGRTMIN+1, &sa, NULL);
...

struct aiocb ac;

ac.aio_filedes = some_fd;
ac.aio_sigevent.sigev_notify = SIGEV_SIGNAL;
ac.aio_sigevent.sigev_signo  = SIGRTMIN+1;   /* Associate callback w. aiocb */
....
aio_read(&ac);

现在你的 my_callback 将在一个线程中异步触发,并由你将fd传递给你的helper线程池。另请参阅this bit of SGI code,了解在SIGEV_SIGNAL不可用时如何回退到SIGEV_CALLBACK

答案 2 :(得分:0)

如果您担心每次完成调用都会创建/销毁多个线程,为什么不批量生成IO?

使用list io apis ..

struct aiocb **myaiocb;
 [just an array of aiocb pointers, where each aiocb points to an IO buffer
  and the operation to be performed, etc]
....
lio_listio(LIO_NOWAIT, myaiocb, num_ios, &sigevent);

列表IO的优点是只有在列表中的所有IO完成(成功/失败)后才会调用回调处理程序。您可以使用aio_return检查每个IO操作的状态。

答案 3 :(得分:0)

这是一个非常古老的帖子,但在查看同样的问题时,它出现在谷歌的顶端。现在有一个GNU扩展[,它允许您指定aio应该使用的最大线程数以及这些线程的生命周期。