为什么父进程的stdin在从分叉子进程关闭stdin文件描述符后仍然接受输入?

时间:2017-07-06 13:13:21

标签: python linux

我正在运行的Linux系统上的

fork(2)手册页说明如下:

  

子进程继承了父进程打开文件描述符的副本。子节点中的每个文件描述符引用相同的打开文件描述(请参阅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而不是子进程。这会为子进程中的EOFError调用提出input()

这看起来像[child]进程写入/修改父文件描述符时,它不会影响[parent]。也就是说,子进程获得更新的文件描述。

那么为什么调用_exit作为Python Docs声明如果子进程执行的操作不影响父进程,则阻止调用清理处理程序?我们来看看_EXIT(2)手册页:

  

函数_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 a SIGCHLD`信号。

     

函数_exit()exit(3)类似,但不调用使用atexit(3)或on_exit(3)注册的任何函数。打开stdio(3)流不会刷新。另一方面,_exit()会关闭打开的文件描述符,这可能会导致未知的延迟,等待挂起的输出完成。

fork()手册页未提及子进程的清除处理程序是从父进程继承的。这对父母有何影响?换句话说,为什么不让孩子过程自我清理,为什么不呢?

1 个答案:

答案 0 :(得分:1)

我假设你是在终端内的shell中运行它。

shell在新进程组中启动Python进程,并使用self.textInput.subscribe(function (newValue) { if(newValue.match(/[a-z]/)) self.responseErrorMessage("Numbers only"); else self.responseErrorMessage(''); }); 将其设置为TTY上的前台进程组。

一旦父Python进程终止,shell将回收终端的控制权(它将自己设置为前台进程组)。 shell不知道Python的分叉子节点仍在运行。

当不属于前台进程组的进程尝试从终端读取时,它通常会收到tcsetpgrp()信号。但是,在这种情况下,进程组已成为孤立状态,因为其领导者已终止,因此子进程在TTY上从SIGTTIN收到EIO错误。 Python将其视为read()