为啥需要关闭另一个进程的管道加上 set_close_on_exec 才能真正关闭?
Posted
技术标签:
【中文标题】为啥需要关闭另一个进程的管道加上 set_close_on_exec 才能真正关闭?【英文标题】:Why does a pipe to another process need to be closed plus set_close_on_exec to really close?为什么需要关闭另一个进程的管道加上 set_close_on_exec 才能真正关闭? 【发布时间】:2018-09-30 10:00:48 【问题描述】:所以,我尝试使用 OCaml 与 Python 进程进行通信。我想将 Python 程序通过管道传输到 Python 解释器的标准输入,然后在 OCaml 进程中读取 Python 程序的输出。
我可以这样解决:
let py_program = |
import time
while True:
print('hi from Python', flush=True)
time.sleep(0.25)
|
let exec_py_program () =
let cmd = "", [|"python3"; "-"|] in
let pipe_out_fd, pipe_out_fd_unix = Lwt_unix.pipe_out () in
(* Close the 1st time *)
let () = Lwt_unix.set_close_on_exec pipe_out_fd_unix in
let redir = `FD_move pipe_out_fd in
let py_stream = Lwt_process.pread_lines ~stdin:redir cmd in
let%lwt n = Lwt_unix.write_string pipe_out_fd_unix py_program 0 (String.length py_program) in
if n < String.length py_program then failwith "Failed to write python to pipe" else
let rec read_back () =
match%lwt Lwt_stream.get py_stream with
| Some str ->
let%lwt () = Lwt_io.printl @@ "Got: " ^ str in
read_back ()
| None -> Lwt.return ()
in
(* Close the 2nd time *)
let%lwt () = Lwt_unix.close pipe_out_fd_unix in
read_back ()
我使用“set_close_on_exec”关闭与映射到Python进程的标准输入的管道对应的文件描述符,靠近注释“关闭第一次”,并在再次发送Python程序后再次关闭管道(“关闭第二次时间”)。 “set_close_on_exec”应该在“当进程在另一个进程上调用 exec 时”关闭文件描述符。
如果我忽略其中任何一行,Python 进程会无限期地继续从其标准输入读取数据并且永远不会开始执行,因此永远不会收到“来自 Python 的 hi”。所以我的问题是,为什么这两个都是必要的?这主要是我的猜测。
【问题讨论】:
【参考方案1】:在 POSIX 操作系统(如 Linux)上启动程序分两步完成。首先,启动程序的进程被分叉,它创建了正在运行的进程的副本。然后,使用对exec
的调用将新进程替换为新程序。当进程被分叉时,两个生成的进程都会继承所有打开的文件描述符。因此,要真正关闭一个文件描述符,它必须在两个进程中都被关闭。
设置 close-on-exec 标志,使进程在调用exec
时立即关闭相应的文件描述符。因此,当您设置此标志时,只有旧进程在程序启动后具有打开的文件描述符。
另见this question。
【讨论】:
以上是关于为啥需要关闭另一个进程的管道加上 set_close_on_exec 才能真正关闭?的主要内容,如果未能解决你的问题,请参考以下文章
为啥python在关闭fifo文件时会生成sigpipe异常?