【问题标题】:Can I rely on Linux close() not blocking for file I/O?我可以依靠 Linux close() 不阻塞文件 I/O 吗?
【发布时间】:2015-07-05 10:08:53
【问题描述】:

我正在使用 Linux aio (io_submit() / io_getevents()) 进行文件 I/O。由于某些操作没有 aio 等效项(open()fsync()fallocate()),因此我使用了一个可能会阻塞而不影响主线程的工作线程。我的问题是,我应该将close() 添加到此列表中吗?

所有文件都在 XFS 上使用O_DIRECT 打开,但我对这个问题的一般答案以及关于我选择的文件系统和打开模式的具体答案都很感兴趣。

请注意,为close() 使用工作线程并非易事,因为在清理路径中经常调用close(),这不是启动工作线程请求并等待它的好地方。所以我希望close() 在这种情况下是非阻塞的。

对于这个问题,“阻塞”是指等待 I/O 操作,或者等待某个只有在 I/O 操作完成时才释放的锁,但不包括页面错误服务。

【问题讨论】:

  • 通过粗略阅读代码,看起来close() 可能会阻塞某些文件系统,但不会阻塞其他文件系统。所以我想我不会得到明确的答案。

标签: linux file blocking aio


【解决方案1】:

close() 可能会在某些文件系统上阻塞。在可能的情况下,代码应尽可能地编写成可移植的。因此,您绝对应该将 close() 添加到仅从阻塞工作线程调用的调用列表中。

但是,您提到您经常需要在清理路径中调用close()。如果这些是在您的应用程序终止时执行的清理路径,那么即使您直接调用 close() 确实会阻塞,它也可能不会产生太大的影响。

或者,您可以做的是有一个队列,该队列被馈送到工作人员池中。在glibc AIO 中,这是对许多呼叫所做的。当您使用aio_init() 初始化AIO 时,glibc 会设置一个队列和一个工作线程池。每次进行 AIO 调用时,glibc 只需将相关任务和数据添加到队列中。在后台,工作线程等待队列并执行阻塞调用和代码,然后执行任何相关操作。

如果您确实需要非阻塞 close()(和其他)调用,那么简单地设置任务队列和线程池并简单地将特定调用提交到队列并拥有线程池在调用时执行调用。

【讨论】:

  • 我确实有一个线程池和一个队列。但是排队需要分配,这可能会失败。这不是你想要的清理路径,因为它可能导致文件描述符泄漏。
  • @AviKivity 排队在您提前准确知道要发送的内容时不需要任何额外的分配。在这种情况下,您将发送任务以调用其参数和参数提前知道的函数。因此,例如,您应该能够使用大小合适的ring buffer。这里是another answer on SO that correctly implements a ring buffer
  • 我不知道我提前有多少 close() 调用,因为我的应用程序不使用固定数量的文件。
  • @AviKivity 当然。但是,您确实知道您的应用程序将进行什么调用。因此,您可以做的是创建一个合理大小的缓冲区(因平台而异),然后,如果有太多东西进入队列,那么一些线程将不得不阻塞,直到队列获得更多空间。
猜你喜欢
  • 1970-01-01
  • 2012-06-18
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-05-24
  • 2018-04-06
  • 1970-01-01
相关资源
最近更新 更多