【问题标题】:Process programming model using Linux pipe()使用 Linux pipe() 的进程编程模型
【发布时间】:2011-08-01 23:54:57
【问题描述】:

来自http://pubs.opengroup.org/onlinepubs/009604599/functions/pipe.html

pipe() 函数将创建一个管道并放置两个文件 描述符,每个进入参数 fildes[0] 和 fildes[1],即 请参阅打开的文件描述的读写端 管道。

有一个例子,父级向其子级写入数据:

int fildes[2];
const int BSIZE = 100;
char buf[BSIZE];
ssize_t nbytes;
int status;


status = pipe(fildes);
if (status == -1 ) {
    /* an error occurred */
    ...
}


switch (fork()) {
case -1: /* Handle error */
    break;


case 0:  /* Child - reads from pipe */
    close(fildes[1]);                       /* Write end is unused */
    nbytes = read(fildes[0], buf, BSIZE);   /* Get data from pipe */
    /* At this point, a further read would see end of file ... */
    close(fildes[0]);                       /* Finished with pipe */
    exit(EXIT_SUCCESS);


default:  /* Parent - writes to pipe */
    close(fildes[0]);                       /* Read end is unused */
    write(fildes[1], "Hello world\n", 12);  /* Write data on pipe */
    close(fildes[1]);                       /* Child will see EOF */
    exit(EXIT_SUCCESS);
}
  1. 我想知道使用管道与其孩子进行通信的父母如何确保在父母运行 write 之前孩子不会运行 read(),而孩子 在家长写完之前读完?

  2. 我想知道在父级中创建的管道是否可以用于 父母和孩子之间的双向沟通​​,或者只是一种方式 父母对孩子不是相反吗?

    如果孩子可以通过管道向父母发送数据,那么 程序长什么样?

  3. 是一个像真正的管道一样有两端的管道。 fildes[0] 和 fildes[1] 分别用来表示两端?

    如果管道是双向的,读端和写端是什么意思 关于,即哪个读(写),父母还是孩子?

感谢和问候!

【问题讨论】:

    标签: linux process pipe


    【解决方案1】:
    1. 除非您指定O_NONBLOCK,否则read 将阻塞并等待数据可用。所以没关系;如果数据尚不可用,它将等待。
    2. 不,管道不是双工的。如果你想要双向通信,你应该做两个管道(总共会给你四个文件描述符)。 fildes[0] 始终是读取(输出)端,fildes[1] 始终是写入(输入)端。因此,您完全按照您的操作设置了一个管道(父级获得写入端,子级获得读取端,因此父级可以发送给子级),然后以相反的方式设置另一个管道(你让父母保持阅读端,让孩子保持写作端)。
    3. fildes[0]fildes[1] 确实代表了管道的末端,但它们不可互换。一种用于将数据“放入”管道,另一种用于从管道“取出”数据。

    如果您需要更多说明,请随时询问;我意识到这可能会让新手感到困惑。

    更新以回答评论中的问题:

    1. 任何进程都可以调用pipe(),并且它的子进程将继承它接收到的文件描述符(除非你关闭它们)。也就是说,它们可以通过多次fork() 调用而存活下来。因此,您可以编写一个程序,将文件描述符提供给孙子、曾孙等。
    2. 当然,两个同级进程可以像这样进行通信。父调用pipe() 来创建对(或者如果您想要双向通信,则创建两个对),然后分叉两次。然后您可以让一个孩子使用fildes[0],而另一个孩子使用fildes[1]。父级不应使用任何文件描述符。瞧!孩子与共同父母之间的交流。这个简单(尽管可能不直观)的功能非常强大,这是非常了不起的。这类似于下面的示例。
    3. fork() 拍照为克隆机。在进入克隆机之前,您使用pipe() 制作一对使用特殊秘密频率的匹配对讲机。一个只能传输;对方只能收。当您使用克隆机时,会出现您的两个副本(原始副本,即父母,以及克隆,即孩子)。每个副本现在都携带一对相同的匹配对讲机。如果原始人破坏了他的“接收”设备而克隆人破坏了他的“传输”设备,那么原始人可以使用对讲机与克隆人交谈(但不能反过来)。

      但是你看,这里的关键思想不是pipe() 连接两个进程(尽管这是它的主要用途),它是在fork() 期间重复的东西。您可以多次重新进入克隆机并获得许多对讲机,因此定义“谁在与谁通话”(哪些进程通过管道连接)并不是克隆机功能的特定方面或对讲机。

      相反,它取决于谁最终实际使用了哪些端点,这完全在您的控制之中。如果你愿意,你可以让孩子关闭两个端点(摧毁两个对讲机),这会让父母自己跟自己说话(这很愚蠢,可能没有用,但它是可能的) .我意识到这有点切题,但我试图传达基本思想的工作原理,以便您了解管道可能实现的领域。

    同级进程与管道通信的示例(单向):

    int fildes[2];
    int status;
    
    status = pipe(fildes);
    if (status == -1) { ... }
    
    // first fork
    switch (fork()) {
    case -1:
        // handle error
        break;
    
    case 0:
        // child 1 (with the writing end -- close the writing end)
        close(fildes[0]);
        // your logic for child 1 here, using fildes[1] to write
        return;
    
    default:
        // not child 1: close the writing end
        close(fildes[1]);
        break;
    }
    
    // second fork
    switch (fork()) {
    case -1:
        // handle error
        break;
    
    case 0:
        // child 2 (with the reading end)
        // your logic for child 2 here, using fildes[0] to read
        return;
    }
    
    // still in the parent
    // logic for the common parent here, after forking both children
    

    【讨论】:

    • 谢谢!在webcache.googleusercontent.com/… 中,“管道只能在具有共同祖先的进程之间使用”。 (1) 但在我的帖子中的示例中,管道用于父子之间的通信。那么共同祖先是什么意思,就像共同的祖父一样? (2) 同一个父母的两个孩子可以通过管道进行通信吗?怎么样?
    • (3) 如果有多个子节点,哪个子节点是在父节点中创建的与父节点相连的管道?
    • 已更新以反映其他问题。
    【解决方案2】:
    1. 如果子进程运行read(),它将阻塞直到数据可用,只要没有为描述符设置no阻塞。如果子进程完成读取并关闭管道,父进程将收到SIGPIPE 信号,write() 将中止。

    2. 管道通常是单向通信。有(谣言)双向管道的实现,但我从未遇到过其中之一。

    3. 如 2. 中所述,管道最初被定义为单向的,因此父级具有写入的终点,子级具有读取的终点。如果双向管道可用,我猜想子可以写入其末端,而父可以从其末端读取。

    也许man 7 pipe 也会对您有所帮助。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2014-03-30
      • 1970-01-01
      • 1970-01-01
      • 2017-07-24
      • 1970-01-01
      • 2012-05-17
      • 1970-01-01
      相关资源
      最近更新 更多