2014-11-01 82 views
1

我想了解三个流的行为 - stdout,stdinstderr。我无法从任何教科书中得到答案,所以我来到了这里。stdin,stdout和stderr在?之间共享?

我知道这三个存储在文件描述符表中,文件描述符为0(标准输入),1(标准输出)和2(标准错误)。我也知道这些不仅仅是文件描述符,而是可以被重定向的I/O流。好的,那么分享怎么样?

考虑三种情况:

  1. 当叉子()被调用:子进程和父进程共享文件描述符,但它们具有相同的标准输入,输出和错误?
  2. 当一个线程被创建时:线程共享文件描述符,但I/O流?
  3. 当execl()被调用时:在这种情况下,当前过程映像被新的过程映像覆盖。如果我这样做execl("./a.out", "a.out", NULL);,那么这个新的可执行文件会得到stdin,stderr和stdout的全新拷贝吗?

明智的答案是值得欢迎的。

回答

2

为了了解发生了什么,请考虑这些是跨越流程边界的沟通渠道。我会避免将它们称为流,因为它们在不同的环境中使用,但它们是相关的。

现在,首先,filedescriptor只是表示这些通道的进程特定表的索引,它们基本上是一种不透明的句柄。但是,下面是第一个答案:由于线程是进程的一部分,因此它们也共享这些描述符,所以如果从两个线程写入同一个通道,它将通过相同的通道,因此在进程之外,两个线程难以区分。

然后,当fork()被调用时,进程被有效地复制。这是通过写入时复制优化来完成的,但这仍然意味着它们也具有代表这些通信通道的不同表格。一个进程中索引为2的条目与fork中索引为2的条目不同。对于进程内的任何结构,如果您创建了C FILE*或C++ std::stream,那么它也会与其他数据一起被复制。

当调用execl()时,进程仍然“拥有”某些通道到外部。这些从管理进程的操作系统分配给它。这意味着指数2仍然可以用于与外界沟通。在启动时,运行时库然后将创建例如FILE *用于C中三个众所周知的频道stdin,stdout和stderr。

问题仍然存在,当一个进程分流到外部渠道时会发生什么。在这里,答案很简单,不管是关闭还是继承,都可以在每个频道的基础上进行配置。如果它是继承的,它仍然可以在子进程中使用。任何写入继承通道的内容都会在父进程的输出结束时结束。

关于分叉过程的标准输入,实际上,我不知道,我觉得输入默认那些被关闭的一个,因为输入发送到多个目标没有意义。另外,我从来没有发现需要实际处理来自子进程中的标准输入的输入,除非该输入是父进程特别提供的(类似于shell中的管道,尽管那些是兄弟而不是父和子)。

注:我不知道,如果这个描述很清楚,请不要犹豫,问我会尽量完善事物的理解。

+0

谢谢你的精心答复。我发现它有点难以接受。据我了解,对于情况2和3,stdin,stdout和stderr是共享的。我无法理解fork()的情况。 你在说如果一个文件被父进程打开,并且被子进程再次打开;这两个文件描述符是独立的? – 0aslam0 2014-11-02 06:31:32

+0

也请在这里检查。 http://stackoverflow.com/questions/26696811/making-stdin-writable-in-a-safe-and-portable-way – 0aslam0 2014-11-02 07:45:14

+0

是的,在情况2个3的标准流被共享,线程总是共享进程和EXECL ()不会更改进程(它只会更改进程运行的内容)。在fork()的情况下,继承的流仍然可用于子进程。在这种情况下,数据从父进程和子进程都流向哪个进程接收数据。 – 2014-11-04 20:51:10

0

让我们假设相反。

如果他们没有共享相同的位置(这基本上是一个文件描述符),那么这些场景将不得不想出一些东西?那是可能的 - 人们可以从确定性的机器得出结论,事实并非如此。

这就是答案。是的,他们共享相同的位置。

+0

很好。这也是我的结论。但是当我试图运行一个小代码来检查它时,我遇到了意想不到的错误。我应该用我的问题补充还是发布一个新问题? – 0aslam0 2014-11-01 08:56:32

+0

@ xachu4u - 那是你的选择 – 2014-11-01 08:57:22