跳到主要内容

Child

搜索

结构体 Child 

Source
pub struct Child {
    pub stdin: Option<ChildStdin>,
    pub stdout: Option<ChildStdout>,
    pub stderr: Option<ChildStderr>,
    /* private fields */
}
展开描述

在事件循环上派生的子进程的表示。

§Caveats

与标准库的行为类似,与 future 范式的“drop 即取消”不同,默认情况下, 派生出的进程即使在 Child 句柄被 drop 后仍会继续执行。

Command::kill_on_drop 方法可用于修改此行为, 当 Child 包装器在子进程退出前被 drop 时终止子进程。

字段§

§stdin: Option<ChildStdin>

用于向子进程的标准输入(stdin)写入的句柄(如果已捕获)。 为了避免在使用 stdin 时部分移动 child, 从而无法在 child 上调用其它函数, 你可能会发现下面的写法很有帮助:

let stdin = child.stdin.take().unwrap();
§stdout: Option<ChildStdout>

用于从子进程的标准输出(stdout)读取的句柄(如果已捕获)。你可能会发现下面的写法很有帮助

let stdout = child.stdout.take().unwrap();

即在使用 stdout 时避免部分移动 child, 从而无法在 child 上调用其它函数。

§stderr: Option<ChildStderr>

用于从子进程的标准错误(stderr)读取的句柄(如果已捕获)。你可能会发现下面的写法很有帮助

let stderr = child.stderr.take().unwrap();

即在使用 stderr 时避免部分移动 child, 从而无法在 child 上调用其它函数。

实现§

Source§

impl Child

Source

pub fn id(&self) -> Option<u32>

在子进程仍在运行时,返回由操作系统分配的与此子进程关联的进程标识符。

子进程被 poll 完成之后,此方法将返回 None。 这是为了避免在 Unix 等操作系统上出现混淆 —— 进程完成后操作系统标识符可能被复用。

Source

pub fn raw_handle(&self) -> Option<RawHandle>

提取与此子进程关联的进程原始句柄(仅在子进程仍在运行时有效)。 如果子进程已退出,则返回 None

Source

pub fn start_kill(&mut self) -> Result<()>

尝试强制子进程退出,但不会等待该请求生效。

在 Unix 平台上,这等效于发送 SIGKILL 信号。 注意在 Unix 平台上,kill 信号发出后仍可能残留僵尸进程; 为避免这种情况,调用者应确保成功调用 child.wait().awaitchild.try_wait()

Source

pub async fn kill(&mut self) -> Result<()>

强制子进程退出。

这等同于在 unix 平台上发送 SIGKILL 信号, 随后调用 wait

注意:标准库的 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"),
    }
}

你还可以与子进程的标准 I/O 交互。 例如,你可以在等待子进程退出的同时读取它的 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");
}
Source

pub async fn wait(&mut self) -> Result<ExitStatus>

等待子进程完全退出,返回其退出状态。 该函数在至少被调用一次之后,仍会返回相同的返回值。

到子进程的 stdin 句柄(如有)在等待之前会被关闭。 这有助于避免死锁:它确保子进程不会因为等待父进程的输入而阻塞, 同时父进程正在等待子进程退出。

如果调用者希望显式控制子进程 stdin 句柄关闭的时机, 可以在调用 .wait() 之前先调用 .take()

§Cancel safety

此函数是可取消安全的。

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;
}
Source

pub fn try_wait(&mut self) -> Result<Option<ExitStatus>>

如果子进程已退出,尝试收集其退出状态。

该函数不会阻塞调用线程,只会检查子进程是否已退出。 如果子进程已退出,在 Unix 上将回收其进程 ID。 只要子进程已经退出,此函数保证能反复返回成功的退出状态。

如果子进程已退出,则返回 Ok(Some(status))。 如果此时退出状态不可用,则返回 Ok(None)。 如果发生错误,则返回该错误。

注意,与 wait 不同,此函数不会尝试 drop stdin, 也不会在子进程退出时唤醒当前任务。

Source

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())

Trait 实现§

Source§

impl Debug for Child

Source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

使用给定的格式化器格式化此值。 更多信息

自动 Trait 实现§

§

impl Freeze for Child

§

impl !RefUnwindSafe for Child

§

impl Send for Child

§

impl Sync for Child

§

impl Unpin for Child

§

impl UnsafeUnpin for Child

§

impl !UnwindSafe for Child

Blanket 实现§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. 更多信息
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. 更多信息
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. 更多信息
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

原样返回传入的参数。

Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

调用 U::from(self)

也就是说,此转换的具体行为取决于 From<T> for U 的实现方式。

Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = Infallible

转换出错时返回的类型。
Source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

执行转换。
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

转换出错时返回的类型。
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

执行转换。