Разрешить родительскому процессу ржавчины завершиться, не дожидаясь подпроцесса

#unix #rust #subprocess

Вопрос:

У меня есть процесс Rust, который должен запустить подпроцесс, а затем немедленно выйти. Похоже, это работает:

 fn main() {
    // Intentionally drop the returned Child and exit
    Command::new("bash").args(amp;["-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
...
 

Однако, если я добавлю еще один слой и попытаюсь вызвать свой двоичный файл и дождаться его завершения, это также приведет к ожиданию подпроцесса, в отличие от того, что я наблюдаю в оболочке. Вот МАКВЕ:

 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(amp;["-c", "sleep 10s; touch done"]).spawn().unwrap();
    }
}
 
 $ cargo build; target/debug/demo
# doesn't terminate until the bash process does
 

Есть ли способ завершить процесс верхнего уровня, не дожидаясь вложенного процесса?

Ответ №1:

Пожалуйста, проверьте ссылку на spawn

Выполняет команду как дочерний процесс, возвращая ей дескриптор.

По умолчанию стандартный ввод данных, стандартный вывод и стандартный вывод данных наследуются от родителя.

Когда вы запускаете себя как подпроцесс, он порождает другой подпроцесс с наследованием stdio от родителя. Поскольку ваш процесс верхнего уровня использует output() его, он будет ждать завершения подпроцесса и собирать все его выходные данные (ссылки).

Давайте продемонстрируем это так:

Корень -> Sub1 ->> >>Sub2

Sub2 использует канал stdout Sub1, Root ожидает сбора всех выходных данных от Sub1, которые все еще используются Sub2, в конце дня Root ожидает завершения Sub2.

Решение таково: просто используйте Stdio::null() для отправки выходных данных /dev/null , так как ваш корневой процесс не заботится о выводе Sub2.

 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(amp;["-c", "sleep 10s; touch done"])
            .spawn()
            .unwrap();
    }
}
 

Комментарии:

1. Потрясающее спасибо, я должен был это понять 🙂