POSIX AIO库和回调处理程序

6 linux posix aio

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

我认为回调函数比信号更受欢迎,并且可能更容易集成到更高级别的多线程库中.不幸的是,至少可以说这个功能的文档很乱.某些源(例如sigevent结构的手册页)指示您需要将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库,而不是每次调用处理程序时创建/销毁新线程?

pil*_*row 1

一种方法是使用SIGEV_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);
Run Code Online (Sandbox Code Playgroud)

现在,您的my_callback将在一个线程中异步触发,您可以将 fd 传递给辅助线程池。另请参阅这段 SGI 代码,演示如何在不可用SIGEV_SIGNAL时回退。SIGEV_CALLBACK

  • 信号的问题在于,如果您是图书馆,则需要在用户的上下文中设置处理程序。这可能会让一些用户感到惊讶和烦恼。 (2认同)