我将使用aio进行异步读取。当aio完成并触发信号处理程序时,我可能需要再执行一次aio_read调用并继续。
安全功能中没有提到aio_read(在man信号中)。但普通的阅读是。
在aio信号处理程序中执行后续aio_read调用有什么危险?
答案 0 :(得分:3)
作为可以使用POSIX AIO的Boost.AFIO的作者,我强烈建议不要使用POSIX AIO。在这种观点中我并不孤单,@ arvid同样反对:http://blog.libtorrent.org/2012/10/asynchronous-disk-io/。 API本身设计很差,因此除非您使用特定于操作系统的替代方案或扩展到像BSD kqueues这样的AIO,否则会导致负载不佳。 POSIX AIO原本无用。
此外,在您可能正在使用的Linux上,AIO调用不是信号安全的。这是因为在Linux上,它们是使用基于线程池的模拟在用户空间中实现的。在BSD上,AIO调用有一个合适的内核系统调用接口,但在内核中转入 - 是的,你猜对了 - 基于线程池的模拟,除非打开O_DIRECT。
因此,除非您的所有i / O都使用O_DIRECT,否则您最好总是使用线程池。如果确实O_DIRECT始终打开,则Linux提供了一个在http://man7.org/linux/man-pages/man2/io_submit.2.html详细说明的自定义内核API,这是相当有效的,如果用BSD kqueues替换信号驱动处理,则在BSD (https://www.freebsd.org/cgi/man.cgi?kqueue ,参见EVFILT_AIO)然后使用O_DIRECT,事情也可以很好地扩展,比线程池更好。
在任何POSIX平台上使用基于信号的完成处理具有可怕性能。 AFIO v2提供了一个通用的POSIX AIO后端,它是可怕的,可怕的,可怕的。像瘟疫一样避免。
请注意,线程化的同步API设计是可移植的,适用于大多数用例,并且是我(实际上是arvid)会向没有高度专业化需求的人推荐的,例如编写数据库后端,您需要对其进行非常严格的控制物理存储层,除了O_DIRECT | O_SYNC之外的任何东西都不是一个选项。
好的,所有这一切,如果你真的想要使用信号驱动的aio,我认为这是因为你想要将你的文件i / o与非文件i / o的东西多路复用,因此你不能使用aio_suspend ()这是执行此操作的正确API。 AFIO v2处理此问题的方法是使用实时信号来中断aio_suspend(),当需要处理非aio相关的内容时,可以处理它并重新启动aio_suspend()。在处理竞争和死锁时你需要非常小心,并且你需要小心地屏蔽和取消屏蔽调用aio_suspend()的线程的信号,以免实时信号丢失并且你失去了唤醒。总而言之,通过线程池+同步API获得通常低得多的i / o性能是不值得的。