哪个是正确的说法?
每个 Unix 进程都打开标准文件描述符:标准输入、标准输出和标准错误。
或者
连接到终端的每个 Unix 进程都打开标准文件描述符:标准输入、标准输出和标准错误。
答案1
他们都错了。
sleep 999 <&- >&- 2>&-
^C
Unix进程sleep 999
没有打开标准文件描述符,但它仍然附加到终端,因为我可以使用 Control-C 杀死它。
答案2
如果这是多项选择题,请勾选第一个。老师想让你理解这些标准文件描述符是通常对任何进程开放,而不仅仅是附加到终端的进程。
但是,除了启动时的第一个进程之外,没有任何进程绝对可以保证通过这些启动。您可以认为第二个陈述更正确,因为如果没有这些打开,它就不再真正附加到终端(有争议)。
什么是真的?
每个进程都被允许关闭()或替换其任何文件描述符,包括 STDIN STDOUT STDERR。一旦关闭,它们就会消失了并且根本不再作为 FD 存在。子进程持有的所有文件描述符都是从父进程继承的。因此,如果一个进程关闭这三个标准文件描述符,然后创建一个子进程,则该子进程也不会拥有它们。
需要明确的是,这是不正确的:
因此,进程创建系统调用会使用三个标准文件描述符创建所有进程,但有些进程会与其终端分离
如果父进程通过关闭其描述符而不用替换它们来与终端分离dup2(),孩子不会有它们。如果那个孩子创造了自己的孩子,那么“孙子”也不会拥有他们......
对于这方面的 posix 参考,您需要了解执行程序通常是通过以下组合完成的:
fork()
启动子进程execve()
在子进程中运行不同的程序
根据 posixfork() 继承所有文件描述符:
子进程应拥有其自己的父进程文件描述符的副本。每个子级的文件描述符应引用与父级相应的文件描述符相同的打开文件描述。
还有一个进一步的绊倒危险。一些文件描述符可以设置为调用时自动关闭执行():
在调用进程映像中打开的文件描述符应在新进程映像中保持打开状态,但设置了执行关闭标志 FD_CLOEXEC 的文件描述符除外。
因此,即使父程序没有显式关闭文件描述符,子程序也可能不存在该文件描述符。
答案3
对于所有充满敌意的评论,我建议以下答案:
这包含 POSIX 标准的链接:
https://pubs.opengroup.org/onlinepubs/009695399/functions/stdin.html
在程序启动时,应预定义三个流,无需显式打开:标准输入(用于读取常规输入)、标准输出(用于写入常规输出)和标准错误(用于写入诊断输出)。打开时,标准错误流未完全缓冲;当且仅当可以确定标准输入和标准输出流不引用交互设备时,标准输入和标准输出流才被完全缓冲。