6

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

我认为回调函数比信号更可取,并且可能更容易集成到更高级别的多线程库中。不幸的是,这个功能的文档至少可以说是一团糟。一些来源,例如sigevent struct 的手册页,表明您需要将 sigevent 结构中的 sigev_notify 数据成员设置为 SIGEV_CALLBACK,然后提供函数处理程序。据推测,处理程序是在同一个线程中调用的。其他文档表明您需要将 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

4 回答 4

2

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

于 2009-11-05T23:54:05.350 回答
1

一种方法是使用SIGEV_SIGNAL带有实时信号的 a将就绪文件描述符“携带”到信号处理程序。实时信号队列和信号处理程序在一个线程中异步执行,因此这种方法在功能上或多或少等同于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 传递给您的辅助线程池。另请参阅这段 SGI 代码,演示如何回退到不可用SIGEV_SIGNAL时。SIGEV_CALLBACK

于 2009-08-05T21:17:25.773 回答
0

If you are worried about several threads being created/destroyed for each completion call, why dont you batch your IOs ?

use 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);

The advantage with list IO is that the callback handler is called only after all the IOs in the list complete (successfully/unsuccessfully). You can check the status of each IO op using aio_return.

于 2010-12-01T17:56:23.517 回答
0

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

于 2016-02-18T17:30:49.177 回答