【问题标题】:Synchronize parent and child without semaphores在没有信号量的情况下同步父母和孩子
【发布时间】:2016-09-11 20:55:51
【问题描述】:

(没有信号量或线程,只有进程)

我想从父文件中读取数据并通过管道将其传递给子文件。 假设文件中的数据是

Is
This
Possible?

现在通过管道阅读“Is”之后

  1. 孩子怎么会知道新数据“This”已经通过并且应该被读取
  2. 通过管道读取“Possible?”后的终止条件是什么,以便孩子在读取父要传递的所有数据后终止

(不使用信号量或线程,只是简单的进程,即分叉)

提前致谢

【问题讨论】:

  • C 还是 C++?它们是不同的语言。请选择一个。
  • @mindriot 有些问题同样适用于两种语言,这是其中之一。它询问管道 I/O,两种情况下的答案都非常相似。
  • EOF 不适合您?
  • 当没有数据可供输入时,管道的读取端会阻塞。当最后一个进程关闭管道的写端时,管道的读端指示 EOF。唯一棘手的一点是,如果您请求读取 256 个字节并且三个短行可用,则将同时读取所有三个。另一方面,如果你有两个管道,一个从子到父,一个从父到子,那么你可以创建同步半双工通信并避免这个问题——尽管你得到了一些其他的(但他们可能没有对你很重要)。
  • 也许您应该发布您的分叉、管道创建和 I/O 代码。如果管道定义正确,您应该不会遇到这些问题。如果您正在使用forkpipe(2),则将文件描述符用于管道的正确“侧”可能会很棘手,特别是如果您需要两个管道[一个用于向子节点发送数据,第二个用于获取数据返回]

标签: c++ c process pipe fork


【解决方案1】:

写入 文件 的父级和读取它的子级将需要您正在考虑的同步。也就是说,如果父母只写了第一行而孩子已经阅读了它,但父母没有写了第二行,那么孩子得到一个过早的EOF。

但是,管道没有。

管道保持打开状态,直到父/发送者关闭它[或子终止]。因此,孩子可以循环阅读,直到收到 EOF。

如果没有数据可用,子进程将自动阻止读取,但不会过早地获得 EOF。如果你愿意,孩子可以通过select(2)poll(2) 来检查可用的数据,但我认为这几乎没有必要。

在父级发送所有数据并且关闭其管道末端之前,子级将不会获得 EOF。

因此,不需要同步。

另一方面,我们可能有一个父母快速发送很多数据,而孩子阅读速度很慢(即)有点落后。最终,[内核] 管道缓冲区“已满”,父级写入将阻塞,直到子级能够“赶上”并耗尽一些数据。因此,没有数据“丢失”。

【讨论】:

  • 我认为您可能需要改写您的第一句话。文件在关闭之前一直保持打开状态。
【解决方案2】:

您可以使用相当普遍的read()fread() API 简单地读取固定数量的数据,并使用这样一个事实,即它们将阻塞直到有更多数据可用或发出文件结束条件的信号。这是将数据通过管道传输到子进程的最直接方法:子进程只需像普通文件一样从stdin 读取,直到遇到“文件结束”条件。

或者,对于更具响应性/性能的设计(或在处理在文件对象上发出信号的硬件时),您需要:

  1. 启用对非阻塞 I/O 的支持
  2. 使用 select() 类似 API 监控您的输入文件描述符/句柄(管道的读取端)
  3. 与事件循环集成(或自己编写一个简单的)
  4. 能够处理意外的可用数据量。
  5. 能够处理来自read()/fread() 和朋友的错误,尤其是EAGAIN
  6. 并且能够处理文件结束条件。

连接起来意味着深入研究特定于操作系统的 API,但幸运的是,它也是一项足够常见的任务,存在大量工具包库(例如 libuv、Qt)并提供一致的抽象/更高级别的 API。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-09-14
    • 1970-01-01
    • 2019-12-30
    • 1970-01-01
    相关资源
    最近更新 更多