unix 让父Rust进程终止而不等待子进程

ykejflvf  于 2023-04-29  发布在  Unix
关注(0)|答案(2)|浏览(296)

我有一个Rust进程,它应该启动一个子进程,然后立即退出。这似乎起作用:

fn main() {
    // Intentionally drop the returned Child and exit
    Command::new("bash").args(&["-c", "sleep 10s; touch done"]).spawn().unwrap();
}

运行此进程立即退出,bash进程继续:

$ cargo build; target/debug/demo

$ ps aux | grep bash
dimo414         35959   0.0  0.0  4278616   1484 s001  S     1:12PM   0:00.00 bash -c sleep 10s; touch done
...
  • 然而 * 如果我再添加一层并尝试调用我的二进制文件并等待它的完成,它似乎也在等待子进程,这与我在shell中观察到的不同。这是一个MCVE:
fn main() {
    let exec = std::env::current_exe().expect("Could not resolve executable location");
    // First re-invoke the same binary and await it
    if std::env::args().len() < 2 {
        println!("Ran Subprocess:\n{:?}", Command::new(exec).arg("").output().unwrap());
    } else {
        // In that subprocess spawn a long-running process but don't wait
        println!("Spawning Subprocess");
        Command::new("bash").args(&["-c", "sleep 10s; touch done"]).spawn().unwrap();
    }
}
$ cargo build; target/debug/demo
# doesn't terminate until the bash process does

有没有一种方法可以让顶级流程在不等待嵌套流程的情况下完成?

esyap4oy

esyap4oy1#

请检查spawn的引用
将命令作为子进程执行,并返回该命令的句柄。
默认情况下,stdin、stdout和stderr从父级继承。
当你把self作为一个子进程运行时,它会产生另一个子进程,继承父进程的stdio。因为你的顶级进程使用output(),它会等待子进程完成并收集它所有的输出(参考)。
让我们这样演示一下:

-〉子1-〉子2

Sub 2使用Sub1的stdout通道,Root等待从Sub1收集Sub 2仍在使用的所有输出,在一天结束时Root等待Sub 2完成。
解决方案是;只需使用Stdio::null()将输出发送到/dev/null,因为您的根进程不关心Sub 2的输出。

fn main() {
    let exec = std::env::current_exe().expect("Could not resolve executable location");
    if std::env::args().len() < 2 {
        println!(
            "Ran Subprocess:\n{:?}",
            Command::new(exec).arg("").output().unwrap()
        );
    } else {
        println!("Spawning Subprocess");
        Command::new("bash")
            .stdout(Stdio::null())
            .stderr(Stdio::null())
            .args(&["-c", "sleep 10s; touch done"])
            .spawn()
            .unwrap();
    }
}
kmpatx3s

kmpatx3s2#

公认的答案对我不起作用。你应该忽略SIGHUP信号:

use std::os::unix::process::CommandExt;

fn main() -> std::io::Result<()> {

    let mut command = std::process::Command::new("bash");
    command.args(["-c", "pwd; sleep 5; touch helloworld"]);

    unsafe {
        command.pre_exec(|| {
            // Ignore SIGHUP signal to prevent child process from being killed when parent exits
            libc::signal(libc::SIGHUP, libc::SIG_IGN);
            Ok(())
        });
    }
    command.spawn()?;

    Ok(())
}

相关问题