从http://pubs.opengroup.org/onlinepubs/009604599/functions/pipe.html :
pipe()函数将创build一个pipe道,并将两个文件描述符分别放入参数fildes [0]和fildes [1]中,这些参数指向pipe道的读写端的打开文件描述。
有一个父母将数据写入其子的例子:
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); }
我想知道如何使用pipe道与其子的沟通的父母可以确保它不会发生,父母运行之前,运行read()并且孩子在父母完成写之前完成读取?
我想知道如果在父母创build一个pipe道可以用于父母和孩子之间的双向沟通,或者只是从父母到孩子的一种方式而不是另一种方式?
如果孩子可以通过pipe道将数据发送给父母,程序将是什么样子?
是一个pipe道,像一个两端的真正的pipe道。 fildes [0]和fildes [1]分别代表两端吗?
如果一个pipe道是双向的,那么对于一个读(写),父或者孩子来说读端和写端的含义是什么?
感谢致敬!
O_NONBLOCK
,否则read
将会阻塞并等待数据可用。 所以没关系; 如果数据不可用,它将等待它。 fildes[0]
始终是读取 (输出)结束, fildes[1]
是写入 (输入)结束。 所以你完全按照你所做的来设置一个管道(父母得到书写结束,孩子读取结束,所以父母可以发送给孩子),并以相反的方式设置另一个管道(你让父母保持阅读的结束,并给孩子写作结束)。 fildes[0]
和fildes[1]
的确代表管道的端部,但它们是不可互换的。 一个用于将数据“放入”管道,另一个用于从管道中取出数据。 如果您需要更多的澄清,请随时询问; 我意识到这可能会让新手感到困惑。
更新回答问题的评论:
pipe()
,其子进程将继承它接收的文件描述符(除非关闭它们)。 也就是说,他们通过多次fork()
调用生存。 所以你可以编写一个程序,将文件描述符给孙辈,曾孙等等,如果你想的话。 pipe()
创建一对(或者如果你想双向通信的话需要两对),然后分叉两次。 然后你可以有一个孩子使用fildes[0]
,另一个孩子使用fildes[1]
。 父母应该既不使用文件描述符。 瞧! 儿童与共同父母之间的沟通。 这个简单的(尽管可能是不直观的)功能是多么的强大。 这看起来像下面的例子。 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
如果孩子运行了read()
,只要没有阻塞被设置为描述符,它就会阻塞直到数据可用。 如果孩子完成阅读并关闭管道,父母将得到一个SIGPIPE
信号和write()
将中止。
管道通常是单向通信。 有(流言),双向管道的实现,但我从来没有遇到过其中之一。
如2所述,管道最初被定义为单向的,所以父母有结束的地方写信给孩子,结束的地方从哪里读取。 如果双向管道可用,我想这个孩子可以写入到最后,而父节点从最后读取。
也许man 7 pipe
也会帮助你。