【发布时间】:2017-07-06 13:13:21
【问题描述】:
fork(2) 我正在运行的 Linux 系统上的手册页显示以下内容:
子级继承父级打开文件描述符集的副本。子文件中的每个文件描述符与父文件中的相应文件描述符引用相同的打开文件描述(请参阅 open(2))。这意味着两个文件描述符共享打开文件状态标志、文件偏移量和信号驱动的 I/O 属性(参见 fcntl(2) 中 F_SETOWN 和 F_SET-SIG 的描述)。
还有 Python 文档提到
_exit()通常只能在fork()之后的子进程中使用。
当然,_exit 不会调用清理处理程序,问题是,如果你看一下这段代码:
newpid = os.fork()
if newpid == 0:
os.close(0)
else:
time.sleep(.25)
input()
尽管子进程关闭了标准输入,但父进程仍然接受来自标准输入的输入。很好,下面是颠倒的代码:
newpid = os.fork()
if newpid == 0:
input()
else:
time.sleep(.25)
os.close(0)
现在,情况正好相反,这次是父进程关闭标准输入,而不是子进程。这会为子进程中的input() 调用引发EOFError。
这看起来就像当 [child] 进程写入/修改父的文件描述符时,它不会影响 [parent]。也就是说,子进程获取更新的文件描述。
那么,如果子进程执行的操作不影响父进程,为什么要调用_exit 以防止调用清理处理程序作为 Python 文档所述?我们来看看_EXIT(2) man page:
函数
_exit() terminates the calling process "immediately". Any open file descriptors belonging to the process are closed; any children of the process are inherited by process 1, init, and the process's parent is sent aSIGCHLD`信号。函数
_exit()类似于exit(3),但不调用任何用atexit(3) 或on_exit(3) 注册的函数。打开的 stdio(3) 流不会被刷新。另一方面,_exit()会关闭打开的文件描述符,这可能会导致未知延迟,等待挂起的输出完成。
fork() 手册页没有提到子进程的清理处理程序是从父进程继承的。这对父母有什么影响?换句话说,为什么不让子进程自行清理,为什么不呢?
【问题讨论】:
-
EOFError不是由于os.close(0)。即使您使用time.sleep(5),您也会立即得到它。 -
如果标准输入被重定向到管道或文件也不会发生。