【问题标题】:File pointers after returning from a forked child process从分叉的子进程返回后的文件指针
【发布时间】:2015-11-24 16:59:10
【问题描述】:

对于在分叉的父进程和子进程之间共享的给定文件描述符,在子进程从同一文件描述符读取后,父进程中的文件位置保持不变是否正常?

这发生在我身上。这是设置:

我正在编写一个 C++ CGI 程序,所以它从标准输入读取 http 请求。在处理 multipart_form 时,我使用中间对象 (Multipart_Pull) 处理标准输入,该对象具有 getc() 方法,该方法检测边界字符串并在每个字段的末尾返回 EOF,因此我可以假装字段的内容是文件。当该字段是文件上传时,我分叉两次,以便将 Multipart_Pull::getc 的结果通过管道传输到运行 ssconvert 的子进程的标准输入,以便从 Excel 文件生成 CSV 文件以供进一步处理。我编写了子进程以将文件指针留在父进程可以拾取它的位置。父进程使用 wait() 来确保子进程在继续之前完成。

为了在开发 Multipart_Pull 时进行测试,我通过打开从真实 multipart_form 请求复制的磁盘文件来伪装标准输入。

伪造stdin时,子进程返回后,父进程读取的第一个字符与子进程启动时读取的第一个字符相同。也就是说,文件指针没有在父文件的副本中移动。

我已经确认子进程实际上是通过运行 gdb 并使用set follow-fork-mode child 跟踪适当的子进程来读取数据的,并且还通过将读取的字符与从中读取的文件进行比较来确认返回时父进程的文件位置读取数据。

当我真正从标准输入读取时,我不认为这会是一个问题,因为(如果我在这里错了,请纠正我),当你从标准输入读取一个字符时,它就永远消失了。

我意识到有一些解决方法可以解决这个特定问题,最简单的方法是忽略 multipart_form 上文件上传之后的任何字段,即父级不会尝试在分叉后继续阅读。但是,我讨厌削弱生产代码或做出不必要的限制,主要是因为我真的只是想了解正在发生的事情。

提前致谢。

【问题讨论】:

标签: c++ c fork file-descriptor


【解决方案1】:

对于在分叉的父进程和子进程之间共享的给定文件描述符,在子进程从同一文件描述符读取后,父进程中的文件位置保持不变是否正常?

既然您提到了fork(),我认为您正在使用符合 POSIX 标准的系统。否则,答案取决于您的 C++ 实现的具体细节。

在 POSIX 术语中,文件描述符和流都是底层“打开文件描述”上的“句柄”类型。在同一个打开的文件描述上可能有多个不同的句柄,可能由不同的进程持有。 fork() 函数是可能出现这种情况的一种方式。

如果对同一个打开文件描述的多个句柄进行操作,POSIX 会显式声明未指定的结果,除非在specific conditions 下。您的子进程通过显式或作为正常进程终止的结果关闭其流来满足其部分要求。然而,根据 POSIX,为了让父级后续使用其流具有指定的行为,它“应在适当的位置执行 lseek() 或 fseek()(根据句柄类型)。”

换句话说,父进程不能依赖子进程对文件偏移量的操作来自动对其可见,事实上,在子进程操作它们的流副本之后,根本不能依赖任何特定的偏移量。

【讨论】:

  • 感谢您的解释和来源,我可以在其中了解有关所涉及问题的更多信息。然而,规范对我来说仍然有点模糊。您提到需要 lseek 或 fseek 的句子是指“显式更改文件偏移量的函数”作为需要执行 seek 命令的谓词。前面的文档区分了读写操作的隐式文件偏移效果和lseek的显式文件偏移效果,
  • @chuckj,是的,标准可能很难解释。我采用任何对流执行读取或写入的函数来更改其显式效果中的文件偏移量。在此基础上,我断言给定的约束适用于您的父进程。
  • @chuckj,实际上,确实考虑到许多流维护内部 I/O 缓冲区,这将干扰同一打开文件描述上看到相同逻辑文件位置的其他句柄。规范的编写范围比仅适应这种情况更广泛,但是如果您考虑缓冲的各种含义(在每个过程中),那么我认为您会理解规范说明其作用的一些原因。
  • 我之前认为由 fork 生成的两个句柄引用了一个描述,因此一个进程中的位置变化在两个进程中都是可见的,并且该描述位于两个进程之外。我认为这是因为系统似乎以某种方式计算有多少进程拥有打开文件的句柄,否则在一个进程中关闭文件会完全关闭它。使用独立进程的内存空间之外的引用计数,期望一个公共文件位置值似乎也是合理的。
  • @chuckj,您认为的大部分内容都是正确的。如果您在一个进程中有一个打开的流,则分叉该进程会创建一个单独的流,该流引用相同的底层打开文件描述。系统确实会跟踪每个打开文件描述上的打开句柄,从而避免在其上的任何句柄保持打开时关闭该 OFD。然而,即使否则这将允许一个公共文件位置,但在流内部缓冲建立文件位置实际是什么的不同视图。流缓冲区属于进程,而不是系统。
猜你喜欢
  • 2010-11-07
  • 2021-11-05
  • 2011-05-17
  • 2010-12-10
  • 2015-12-12
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-11-30
相关资源
最近更新 更多