【问题标题】:Self implementation of pipe, how to know how many processes has file descriptors to my pipe?管道的自我实现,如何知道有多少进程对我的管道有文件描述符?
【发布时间】:2014-12-12 09:45:24
【问题描述】:

我需要自己实现一个管道,它将具有pipe()read()write()close() 的常规管道式功能。管道旨在用作父进程和子进程之间的通信通道,这意味着程序将使用fork(),可能不止一次。

我的想法是使用 pipe() 函数中的 malloc 来实现它,该函数将在 close() 函数中释放,但是当 fork 命令发生时,我最终会得到多个进程持有一个文件描述符到我的管道,这是我无法弄清楚的部分:

我怎么知道fork() 被调用了多少次以及有多少进程可以访问我的管道? 如何防止关闭其对管道一端的访问的进程为所有其他进程关闭它?如何确保关闭管道的最后一个进程将释放其内存?

更新

实际上它是用来处理文件描述符的,进程不管理这个内存,他们只能访问它,我需要一种方法来防止进程关闭一端在它之前关闭它被所有其他人关闭,并确保一旦所有端都关闭,内存就会被释放。

【问题讨论】:

  • 使用 fork,您可以获得完全分离的进程,每个进程都有自己的内存。因此,仅使用 malloc 的幼稚方法是行不通的 - 您应该在 每个 分叉进程中释放内存
  • 你是在内核内部做这个,还是在普通用户空间代码中模拟它?我假设是后者,但这会使您的生活复杂化,尤其是因为其中一个子进程本身可能会分叉,并且很难追踪到它。在可以正确完成此类跟踪的内核中具有优势。
  • 如果你真的想在不使用内核管道的情况下实现管道,我会看看例如shared memory segments,请参阅教程 here。但显然这不是一个完整的自己动手实现
  • 内存被不同的散文分配,父子俩都只是获得了对该内存的引用。
  • @petric,我认为如果你能给出你的 original 问题的完整描述会很有用。正如您所想象的那样,用户空间管道在用户空间中实际上是不可能的(例如,自定义文件描述符需要编写内核空间模块)。

标签: c linux pipe fork file-descriptor


【解决方案1】:

我认为您想要做的是实现类似pipe() 的东西,但实际上不使用pipe()(甚至是FD),而是使用内存。

当程序执行 fork() 时,其 FD 对子和父都可用。因此,使用pipe(),孩子可以写,而父母可以读(反之亦然)。但是,子代继承了父代内存的写时复制副本。因此,孩子执行的任何写入操作都不会被父母看到,反之亦然。另一方面,如果您使用线程,则内存映射是真正共享的。

您正在尝试做的是 IPC(进程间通信)的一种形式。如果您不想使用内存,则需要一种特殊类型的内存。一种方法是使用shmgetshmctl 等——例如here

但是,您必须自己管理内存分配,而不是使用malloc()free()malloc()free() 在堆上操作,不会使用共享内存段。

为了完整起见,从技术上讲,您的问题的答案是父级和所有子级必须每个释放父级在fork() 之前所做的任何分配,因为他们每个人不仅拥有分配内存的副本,也是内存分配控制结构。但是,它们实际上都有一个包含相同数据的不同分配(通过写时复制实现)。

【讨论】:

  • 实际上它是用来处理文件描述符的,进程不管理这个内存,他们只能访问它,我需要一种方法来防止进程关闭一端在它被所有其他人关闭之前关闭它,并确保一旦所有端都关闭,内存就会被释放。
  • @petric:如果您关心哪一端先关闭管道,那么在需要先关闭的一端关闭之前不要关闭另一端。您可以使用正常的 FD 语义来确定管道已关闭(例如,select 表示它已准备好读取,但 read 给出 0 个字节)。然后使最后一个结束关闭做释放。
  • 我的实现将不仅通过我的代码进行测试,因此我无法真正控制哪个结束以及何时结束。
  • 我认为您可能需要澄清您的问题。如果另一端可靠地关闭了连接,那么只需在此之后关闭您的一端。如果另一端不能可靠地关闭连接,并且您无法释放共享内存,直到它关闭,据我所知,您可以无限期地等待它关闭它。
  • 另一端会关闭它的连接,问题是我不知道有多少进程会有我的FD,也不知道谁是最后一个关闭它并释放内存.
【解决方案2】:

我不确定您的确切想法,但有些选项是:

  1. 使用每个子级打开并递增的命名信号量,等待它在父级中返回 0。这是最简单、最有效的方法。
  2. 获取每个孩子的 PID 并使用等待函数“wait()、wait3()、wait4()、waitpid()”之一来确保它们都已退出。如果您的孩子不退出,程序可能会挂起。
  3. 解析系统“lsof”命令的输出。这个命令可以直接在命名文件上运行,效率不是很高。

【讨论】:

    【解决方案3】:

    我认为您应该查看与 execve() 一起使用的 waitpid 手册。 它为您提供子进程的返回值。

    你可以在 github 上查看我自己的实现:

    https://github.com/sirignano/environnement_unix_1/tree/master/42sh

    我认为 ft_pipe.c 和 ft_use.c 就是你要找的。 (不太确定:D)

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2018-11-29
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多