如果我使用 exec 系列函数之一打开子进程,到父进程的管道是否会应用于子进程?

如果我使用 exec 系列函数之一打开子进程,到父进程的管道是否会应用于子进程?

假设我打开一个带有主进程的父进程,该主进程将标准输出分配给一个文件以进行日志记录。

然后假设我使用父进程通过 execvp (或任何其他 exec 系列函数)打开子进程。

根据文件,子进程将保留父进程的进程ID

主要问题:这是否意味着子进程将继承父进程的管道(特别是 stdout 和 stderr)?

答案1

对于记录的答案,我们需要查看 exec 系列函数调用的系统调用的手册页,执行:

默认情况下,文件描述符在 execve() 期间保持打开状态。标记为 close-on-exec 的文件描述符被关闭;参见 FD_CLOEXEC 的描述fcntl(2)

因此,如果进程未在管道的文件描述符中设置 close-on-exec 标志,则它们在执行后将保持打开状态。

答案2

是的,使用 exec 并继承与父进程相同的 pid 意味着子进程默认保持管道连接,只要文件描述符没有标记为 close-on-exec (这可以通过福康特尔,参见马克·普洛特尼克的回答)。

当我写下我的问题时,我正处于用经验数据进行自我回答的边缘,然后我进行了自我回答,所以我是这样做的:

在文件中master.py

import subprocess
import logging

def main():
    proc = ['python', 'parent.py']
    logpath = 'parent.log'
    with open(logpath, 'ab') as f:
        p = subprocess.Popen(proc, stdout=f, stderr=subprocess.STDOUT)
        logging.warn('task started, waiting to finish')
        res = p.wait()
        logging.warn(res)

if __name__ == '__main__':
    main()

parent.py

import os
import logging

def main():
    proc = ['python', 'child.py']
    logging.warn('parent is logging, pid: {0}'.format(os.getpid()))
    os.execvp(proc[0], proc)

if __name__ == '__main__':
    main()

并在child.py

import os
import logging
import time

def main():
    for i in range(2):
         logging.warn('child is logging, pid: {0}'.format(os.getpid()))
         time.sleep(15)

if __name__ == '__main__':
    main()

当我python master.py在命令行上运行时,命令行输出:

WARNING:root:task started, waiting to finish

大约 15 秒后:

WARNING:root:0

并且parent.log 文件包含以下内容:

WARNING:root:parent is logging, pid 8515
WARNING:root:child is logging, pid 8515
WARNING:root:child is logging, pid 8515

这根据经验证明,当使用 exec 系列函数时,子进程会从父进程继承管道和 pid。很难找到这方面的支持文档,但有一个例子在这里给出(大约材料的一半。)

相关内容