Структура Child
pub struct Child {
pub stdin: Option<ChildStdin>,
pub stdout: Option<ChildStdout>,
pub stderr: Option<ChildStderr>,
/* private fields */
}
process.Представление дочернего процесса, запущенного в цикле обработки событий.
Особенности
Как и в стандартной библиотеке, в отличие от парадигмы futures, согласно которой удаление подразумевает отмену, запущенный процесс по умолчанию продолжит выполняться, даже если дескриптор Child был удалён.
Метод Command::kill_on_drop можно использовать, чтобы изменить это поведение и завершить дочерний процесс, если обёртка Child удалена до его завершения.
Поля
stdin: Option<ChildStdin>Дескриптор для записи в стандартный ввод дочернего процесса (stdin), если он был перехвачен. Чтобы избежать частичного перемещения child и, как следствие, невозможности вызывать функции для child при использовании stdin, может быть полезно сделать следующее:
let stdin = child.stdin.take().unwrap();stdout: Option<ChildStdout>Дескриптор для чтения из стандартного вывода дочернего процесса (stdout), если он был перехвачен. Может быть полезно сделать следующее:
let stdout = child.stdout.take().unwrap();чтобы избежать частичного перемещения child и, как следствие, невозможности вызывать функции для child при использовании stdout.
stderr: Option<ChildStderr>Дескриптор для чтения из стандартного потока ошибок дочернего процесса (stderr), если он был перехвачен. Может быть полезно сделать следующее:
let stderr = child.stderr.take().unwrap();чтобы избежать частичного перемещения child и, как следствие, невозможности вызывать функции для child при использовании stderr.
Реализации
impl Child
pub fn id(&self) -> Option<u32>
Возвращает назначенный операционной системой идентификатор процесса, связанный с этим дочерним процессом, пока он продолжает выполняться.
После завершения дочернего процесса этот метод будет возвращать None. Это сделано, чтобы избежать путаницы на таких платформах, как Unix, где идентификатор операционной системы может быть повторно использован после завершения процесса.
pub fn raw_handle(&self) -> Option<RawHandle>
Извлекает необработанный дескриптор процесса, связанного с этим дочерним процессом, пока он продолжает выполняться. Возвращает None, если дочерний процесс завершился.
pub fn start_kill(&mut self) -> Result<()>
Пытается принудительно завершить дочерний процесс, но не дожидается выполнения запроса.
На платформах Unix это эквивалентно отправке SIGKILL. Обратите внимание, что на платформах Unix после отправки сигнала завершения может остаться процесс-зомби; чтобы этого избежать, вызывающая сторона должна убедиться, что успешно вызван либо child.wait().await, либо child.try_wait().
pub async fn kill(&mut self) -> Result<()>
Принудительно завершает дочерний процесс.
На платформах unix это эквивалентно отправке SIGKILL, за которой следует wait.
Обратите внимание: версия std метода Child::kill не wait. Для эквивалента Child::kill в стандартной библиотеке используйте start_kill.
Примеры
Если дочерний процесс нужно завершить удалённо, это можно сделать с помощью комбинации макроса select! и канала oneshot. В следующем примере дочерний процесс будет выполняться до завершения, если только в канал oneshot не будет отправлено сообщение. Если это произойдёт, дочерний процесс будет немедленно завершён с помощью метода .kill().
use tokio::process::Command;
use tokio::sync::oneshot::channel;
#[tokio::main]
async fn main() {
let (send, recv) = channel::<()>();
let mut child = Command::new("sleep").arg("1").spawn().unwrap();
tokio::spawn(async move { send.send(()) });
tokio::select! {
_ = child.wait() => {}
_ = recv => child.kill().await.expect("kill failed"),
}
}Вы также можете взаимодействовать со стандартными потоками ввода-вывода дочернего процесса. Например, можно читать его stdout, пока вы ожидаете его завершения.
#[tokio::main]
async fn main() {
let (_tx, rx) = channel::<()>();
let mut child = Command::new("echo")
.arg("Hello World!")
.stdout(Stdio::piped())
.spawn()
.unwrap();
let mut stdout = child.stdout.take().expect("stdout is not captured");
let read_stdout = tokio::spawn(async move {
let mut buff = Vec::new();
let _ = stdout.read_to_end(&mut buff).await;
buff
});
tokio::select! {
_ = child.wait() => {}
_ = rx => { child.kill().await.expect("kill failed") },
}
let buff = read_stdout.await.unwrap();
assert_eq!(buff, b"Hello World!\n");
}pub async fn wait(&mut self) -> Result<ExitStatus>
Ожидает полного завершения дочернего процесса и возвращает статус завершения. После первого вызова эта функция будет возвращать одно и то же значение.
Перед ожиданием будет закрыт дескриптор stdin дочернего процесса, если он есть. Это помогает избежать взаимной блокировки: дочерний процесс не будет ожидать ввод от родительского процесса, пока родительский процесс ожидает завершения дочернего.
Если вызывающая сторона хочет самостоятельно управлять моментом закрытия дескриптора stdin дочернего процесса, она может закрыть .take() перед вызовом .wait():
Безопасность при отмене
Эту функцию можно безопасно отменять.
use tokio::io::AsyncWriteExt;
use tokio::process::Command;
use std::process::Stdio;
#[tokio::main]
async fn main() {
let mut child = Command::new("cat")
.stdin(Stdio::piped())
.spawn()
.unwrap();
let mut stdin = child.stdin.take().unwrap();
tokio::spawn(async move {
// do something with stdin here...
stdin.write_all(b"hello world\n").await.unwrap();
// then drop when finished
drop(stdin);
});
// wait for the process to complete
let _ = child.wait().await;
}pub fn try_wait(&mut self) -> Result<Option<ExitStatus>>
Пытается получить статус завершения дочернего процесса, если он уже завершился.
Эта функция не блокирует вызывающий поток и только проверяет, завершился ли дочерний процесс. Если дочерний процесс завершился, то в Unix идентификатор процесса освобождается. Гарантируется, что эта функция будет снова возвращать успешный статус завершения, если дочерний процесс уже завершился.
Если дочерний процесс завершился, возвращается Ok(Some(status)). Если статус завершения пока недоступен, возвращается Ok(None). При возникновении ошибки возвращается эта ошибка.
Обратите внимание: в отличие от wait, эта функция не пытается закрыть stdin и не пробуждает текущую задачу при завершении дочернего процесса.
pub async fn wait_with_output(self) -> Result<Output>
Возвращает future, который завершится значением Output, содержащим код завершения, stdout и stderr дочернего процесса.
Возвращённый future одновременно ожидает завершения дочернего процесса и собирает весь оставшийся вывод из дескрипторов stdout/stderr, возвращая экземпляр Output.
Дескриптор stdin дочернего процесса, если он есть, будет закрыт перед ожиданием. Это помогает избежать взаимной блокировки: так гарантируется, что дочерний процесс не будет заблокирован в ожидании ввода от родительского процесса, пока родительский процесс ожидает завершения дочернего.
По умолчанию stdin, stdout и stderr наследуются от родительского процесса. Чтобы перехватить вывод в этот Output, необходимо создать новые каналы между родительским и дочерним процессами. При создании Command используйте соответственно stdout(Stdio::piped()) или stderr(Stdio::piped()).
Реализации трейтов
Автоматические реализации трейтов
impl !RefUnwindSafe for Child
impl !UnwindSafe for Child
impl Freeze for Child
impl Send for Child
impl Sync for Child
impl Unpin for Child
impl UnsafeUnpin for Child
Общие реализации
impl<T> BorrowMut<T> for Twhere T: ?Sized,
fn borrow_mut(&mut self) -> &mut T
impl<T> Instrument for T
fn instrument(self, span: Span) -> Instrumented<Self> ⓘ
fn in_current_span(self) -> Instrumented<Self> ⓘ
impl<T> WithSubscriber for T
fn with_subscriber<S>(self, subscriber: S) -> WithDispatch<Self> ⓘ
fn with_current_subscriber(self) -> WithDispatch<Self> ⓘ
Subscriber к этому типу и возвращает обёртку WithDispatch. Подробнее
MIT License
Copyright © Tokio Contributors
https://docs.rs/tokio/1.53.1/tokio/process/struct.Child.html