2017-07-06 75 views
1

fork(2)我运行在Linux系统上的手册页说以下内容:为什么父进程的标准输入在关闭分叉子进程的标准输入文件描述符后仍然接受输入?

The child inherits copies of the parent's set of open file descriptors. Each file descriptor in the child refers to the same open file description (see open(2)) as the corresponding file descriptor in the parent. This means that the two file descriptors share open file status flags, file offset, and signal-driven I/O attributes (see the description of F_SETOWN and F_SET‐SIG in fcntl(2)).

和Python文档中提到

_exit() should normally only be used in the child process after a fork() .

当然,_exit不会调用清理处理程序,问题是, ,如果你看这个代码,例如:

newpid = os.fork() 
if newpid == 0: 
    os.close(0) 
else: 
    time.sleep(.25) 
    input() 

父进程仍然接受输入尽管事实上子进程关闭了标准输入,但来自stdin。那好,下面的代码逆转:

newpid = os.fork() 
if newpid == 0: 
    input() 
else: 
    time.sleep(.25) 
    os.close(0) 

现在,它的对面,这个时候,关闭标准输入不是孩子的父进程。这在子进程中调用input()调用EOFError

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

那么为什么打电话_exit作为Python文档状态来防止调用清理处理程序,如果由子进程执行的操作不影响父进程?让我们来看看_EXIT(2)手册页:

The function _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` signal.

The function _exit() is like exit(3) , but does not call any functions registered with atexit(3) or on_exit(3). Open stdio(3) streams are not flushed. On the other hand, _exit() does close open file descriptors, and this may cause an unknown delay, waiting for pending output to finish.

fork()手册中没有提到的是,子进程的清理处理继承自父。这对父母有什么影响?换句话说,为什么不让孩子过程自己清理,为什么不呢?

+1

'EOFError'不是由'os.close(0)'造成的。即使你使用'time.sleep(5)',你也可以立即得到它。 – Barmar

+1

如果stdin被重定向到管道或文件,它也不会发生。 – Barmar

回答

1

我假设你从终端内的shell运行这个。

shell在新进程组中启动Python进程,并使用tcsetpgrp()将其设置为TTY上的前台进程组。

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

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

+0

错误发生在pareent进程终止之前。放置更长的'time.sleep',你会在父亲退出前立即看到'EOFError'。 – Barmar

+0

此外,如果将其更改为'print(input())',则会在报告错误之后成功读取输入。 – Barmar

+0

@Barmar这不是我在Linux机器上观察到的行为。 – ephemient

相关问题