我试图了解三个流的行为 - stdout
,stdin
和stderr
。我无法从任何教科书中得到答案,所以我来到这里。
我知道这三个存储在文件描述符表中,文件描述符为0(stdin),1(stdout)和2(stderr)。我也知道这些不仅仅是文件描述符,而是可以重定向的I / O流。好的,分享怎么样?
考虑以下三种情况:
execl("./a.out", "a.out", NULL);
,那么这个新的可执行文件是否会获得stdin,stderr和stdout的全新副本?欢迎所有明智的答案。
答案 0 :(得分:3)
为了了解发生了什么,请考虑这些是跨越流程边界的沟通渠道。我会避免将它们称为流,因为它们在不同的上下文中使用,但它们是相关的。
现在,首先,filedescriptor只是表示这些通道的特定于流程的表的索引,它们基本上是一种不透明的句柄。但是,这是第一个答案:由于线程是进程的一部分,它们也共享这些描述符,因此如果从两个线程写入同一个通道,它将通过相同的通道离开,因此在进程外部,两个线程无法区分。
然后,当调用fork()时,将有效地复制该进程。这是通过写时复制优化完成的,但仍然意味着它们也有不同的表来表示这些通信通道。索引2在一个进程中的条目与fork中索引为2的条目不同。这对于进程内部的任何结构都是相同的,如果您在一个结构上创建了C FILE*
或C ++ std::stream
,它也会被复制,以及其他数据。
当调用execl()时,该过程仍然拥有"某些渠道到外面。这些是从管理进程的OS分配给它的。这意味着索引2仍可用于与外界通信。在启动时,运行时库将创建例如FILE *用于C中的三个着名频道stdin,stdout和stderr。
剩下的问题是当一个进程分支到外部的通道时会发生什么。在这里,答案很简单,无论是关闭还是继承通道,都可以在每个通道的基础上进行配置。如果它是继承的,它仍然可以在子进程中使用。写入继承通道的任何内容都将在父进程的输出结束的任何地方结束。
关于分叉过程的标准输入,我实际上不确定,我认为输入默认是关闭的输入之一,因为向多个目标发送输入并没有意义。此外,我从未发现需要在子进程中实际处理来自stdin的输入,除非该进程是由父进程专门提供的(类似于shell中的管道,尽管这些是兄弟而不是父和子)。
注意:我不确定此说明是否清楚,请不要犹豫,我会尽力改善您的理解。
答案 1 :(得分:0)
让我们假设相反。
如果他们没有共享相同的位置(基本上是文件描述符),那么这些场景将不得不让人想起什么?这是可能的 - 人们可以从确定性机器得出结论,而不是。
答案就在于此。是的,他们共享相同的位置。