【问题标题】:How does pipe works in c?管道如何在c中工作?
【发布时间】:2019-08-01 11:22:25
【问题描述】:

所以我对 c 中的管道有 2 个问题:

1:

当我在创建管道后 fork 一个进程以使父进程写入管道而子进程从中读取时,它是如何同步的? :父级总是在子级尝试读取数据之前发送数据,尽管它们同时运行? 为什么我不认为孩子在父母尝试发送数据之前就开始阅读?

2:

这是关于管道的文件描述符,参考下面的代码父进程如何在子进程尚未访问该文件时关闭管道输出文件描述符? em> ,假设父母先开始。

任何帮助将不胜感激,谢谢!

#include <stdio.h>                                                                                 
#include <stdlib.h>                                                             
#include <unistd.h>                                                             
#include <sys/wait.h>                                                            
#include <stdlib.h>

#define BUFFER_SIZE  256

int main(int argc , char*argv[])
{
pid_t  worker_pid ;
int descriptor[2];
unsigned char bufferR[256] , bufferW[256];

/***************************** create pipe ********************/

puts("pipe creation");
if (pipe(descriptor) !=0)
    {
        fprintf(stderr,"error in the pipe");
        exit(1);
    }

/***************************** create processes ********************/

puts("now fork processes");
worker_pid = fork(); // fork process 
if (worker_pid == -1 ) // error forking processes
    {
        fprintf(stderr,"error in fork");
        exit(2);
    }


/*********************** communicate processes ********************/

if (worker_pid == 0) // in the child process :  the reader
    {
     close(descriptor[1]); // close input file descriptor , ok because parent finished writing
     read(descriptor[0],bufferR,BUFFER_SIZE);
     printf("i'm the child process and i read : %s \n",bufferR);
    }


if (worker_pid !=0)
    {
       // is there any case where child attempts to read before parent writting ?
       close(descriptor[0]);// close file descriptor of child before it reads ?
       sprintf(bufferW,"i'm the parent process my id is %d , and i wrote this to my child",getpid());
       write(descriptor[1],bufferW,BUFFER_SIZE);
       wait(NULL); 
    }
    return 0;
}

我预计 问题 1 会有一些情况,输出为: i'm the child process and i read :

因为父母还没有写它的消息

对于问题 2,我预计会出现以下错误:

子进程中的文件描述符无效,因为父进程已经关闭它(假设父进程总是第一个运行)

但实际输出始终是: i'm the child process and i read: i'm the parent process my id is 7589, and i wrote this to my child

【问题讨论】:

标签: c linux pipe file-descriptor


【解决方案1】:

当我在创建管道后 fork 一个进程以使 父母写入管道,孩子从管道中读取,怎么样 同步? :父母总是在孩子尝试之前发送数据 读取这些数据,尽管它们同时运行? 为什么我 不要落在孩子先于父母开始阅读的情况 尝试发送它的数据?

通常,它不需要进行同步,实际上它本身可以用作同步机制。如果您执行阻塞读取(默认),那么在发送相应数据之前它们不会完成,无论初始读取和写入调用的相对顺序如何。

然而,这两个过程确实需要实施适当的机制来划分和识别消息边界,以便阅读器能够识别并适当地响应短读。这可能就像用换行符结束每条消息并使用fgets() 读取消息一样简单(通过通过fdopen() 获得的流)。

这是关于管道的文件描述符,参考下面的代码父进程如何在子进程尚未访问该文件时关闭管道输出文件描述符?,假设父母先开始。

不是问题。一旦子代被分叉,它就可以通过父代可以使用的相同文件描述符编号访问它从父代继承的底层打开文件描述,但这些与父代是分开的,目的是确定每次打开的次数文件描述被引用。这种情况类似于dup() 系统调用的操作所导致的情况。只有当 all 进程关闭 all 它们针对给定打开文件描述的文件描述符时,打开文件描述才会失效。

【讨论】:

    【解决方案2】:

    这是在内核内部完成的。当您尝试从文件描述符(管道或套接字)中读取时,如果“远程端”没有发送任何数据,您的进程就会停止(对 read 的调用根本不会返回),直到另一方已将某些内容推入内核的内部缓冲区(在您的示例中,写入管道)。

    这里可以看到linux中管道的内部实现: https://github.com/torvalds/linux/blob/master/fs/pipe.c#L272

    查找变量do_wakeup

    【讨论】:

      猜你喜欢
      • 2011-08-15
      • 2015-02-08
      • 2010-11-07
      • 1970-01-01
      • 2011-06-25
      • 1970-01-01
      • 2016-01-21
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多