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()
尽管子进程关闭了stdin,但父进程仍接受来自stdin的输入 . 这很好,这里的代码反转了:
newpid = os.fork()
if newpid == 0:
input()
else:
time.sleep(.25)
os.close(0)
现在,情况正好相反,这次父进程关闭stdin而不是子进程 . 这为子进程中的 input()
调用提出了 EOFError
.
这看起来像[child]进程写入/修改父文件描述符时,它不会影响[parent] . 也就是说,子进程获得更新的文件描述 .
那么为什么调用 _exit
作为Python Docs声明如果子进程执行的操作不影响父进程,则阻止调用清理处理程序?我们来看看 _EXIT(2)
手册页:
函数_exit()“立即”终止调用进程 . 属于该过程的任何打开的文件描述符都将被关闭;进程的任何子进程都由进程1,init继承,并且进程的父进程发送一个SIGCHLD`信号 . 函数_exit()类似于exit(3),但不调用使用atexit(3)或on_exit(3)注册的任何函数 . 打开stdio(3)流不会刷新 . 另一方面,_exit()会关闭打开的文件描述符,这可能会导致未知的延迟,等待挂起的输出完成 .
fork()
手册页没有提到子进程的清理处理程序是从父进程继承的 . 这对父母有何影响?换句话说,为什么不让孩子过程自我清理,为什么不呢?
1 回答
我假设你是从终端内的shell运行它 .
shell在新进程组中启动Python进程,并使用
tcsetpgrp()
将其设置为TTY上的前台进程组 .一旦父Python进程终止,shell就会回收对终端的控制(它将自己设置为前台进程组) . shell不知道Python的分叉子节点仍然在运行 .
当不属于前台进程组的进程尝试从终端读取时,它通常会收到
SIGTTIN
信号 . 但是,在这种情况下,进程组已成为孤立状态,因为其进程已终止,因此子进程在TTY上从read()
收到EIO
错误 . Python将其视为EOFError
.