POSIX AIO库和回调处理程序

6
根据aio_read/write文档,AIO库通知应用程序异步文件I/O操作已完成的基本方法有两种:1)使用信号;2)使用回调函数。我认为回调函数比信号更可取,并且可能更容易集成到更高级别的多线程库中。不幸的是,这个功能的文档非常混乱。一些来源(例如sigevent结构的man页面)表明,您需要将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个回答

2

我通常发现,通过在专门的后台线程中进行普通 IO 操作,模拟异步 IO 更加简单和可移植,并按照我喜欢的方式分派完成回调。


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

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

2
信号的问题在于,如果你是一个库,你会在用户的上下文中设置处理程序。这可能会让一些用户感到惊讶和烦恼。 - n-alexander
确实,这非常糟糕。库除了暂时屏蔽信号外,不应该触及信号。 - R.. GitHub STOP HELPING ICE

0

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

使用列表IO API...

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操作的状态。

0

这是一个非常古老的线程,但当我搜索这个问题时,它出现在了谷歌的首位。现在有一个GNU扩展aio_init,可以让您指定aio应该使用的线程数的最大值和这些线程的生命周期。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接