为什么需要关闭通向另一个进程的管道再加上set_close_on_exec才能真正关闭?

时间:2018-09-30 10:00:48

标签: ocaml

因此,我试图使用OCaml与Python进程进行通信。我想将Python程序通过管道传递到Python解释器的stdin,然后在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”关闭与注释“ Close the first time”附近映射到Python进程的stdin的管道相对应的文件描述符,并在再次发送Python程序后再次关闭管道(“ Close the 2nd时间”)。 “ set_close_on_exec”应该“在该进程在另一个进程上调用exec时”关闭文件描述符。

如果我不选择其中任何一行,Python进程将无限期地从其stdin中读取数据,并且永远不会开始执行,因此永远不会收到“ hi from Python”。所以我的问题是,为什么这两个都是必要的?这主要是我的猜测。

1 个答案:

答案 0 :(得分:2)

在POSIX操作系统(如Linux)上启动程序分两个步骤。首先,将启动程序的进程进行分叉,这将创建正在运行的进程的副本。然后,使用对exec的调用将新进程替换为新程序。对进程进行分叉时,两个结果进程都会继承所有打开的文件描述符。因此,要实际上关闭文件描述符,必须在两个进程中都将其关闭。

设置close-on-exec标志将导致进程在调用exec后立即关闭相应的文件描述符。因此,当您设置此标志时,在程序启动后,只有旧进程才具有打开的文件描述符。

另请参阅this question