tokio::time::timeout 之后再次等待 future

mal*_*tor 5 rust async-await rust-tokio

背景:
我有一个进程,用于tokio::process在 tokio 运行时生成带有句柄的子进程。

它还负责在杀死子进程后释放资源,并且根据文档(s​​td::process::Childtokio::process::Child),这需要父进程wait()(或await在 tokio 中)进行该进程。

SIGINT并非所有进程对 a或 a 的行为都相同SIGTERM,因此我想在发送 a 之前给孩子一些时间来死掉SIGKILL

所需的解决方案:

    pub async fn kill(self) {
        // Close input
        std::mem::drop(self.stdin);

        // Send gracefull signal
        let pid = nix::unistd::Pid::from_raw(self.process.id() as nix::libc::pid_t);
        nix::sys::signal::kill(pid, nix::sys::signal::SIGINT);

        // Give the process time to die gracefully
        if let Err(_) = tokio::time::timeout(std::time::Duration::from_secs(2), self.process).await
        {
            // Kill forcefully
            nix::sys::signal::kill(pid, nix::sys::signal::SIGKILL);
            self.process.await;
        }
    }
Run Code Online (Sandbox Code Playgroud)

但是给出了这个错误:

error[E0382]: use of moved value: `self.process`
  --> src/bin/multi/process.rs:46:13
   |
42 |         if let Err(_) = tokio::time::timeout(std::time::Duration::from_secs(2), self.process).await
   |                                                                                 ------------ value moved here
...
46 |             self.process.await;
   |             ^^^^^^^^^^^^ value used here after move
   |
   = note: move occurs because `self.process` has type `tokio::process::Child`, which does not implement the `Copy` trait
Run Code Online (Sandbox Code Playgroud)

如果我遵守并删除self.process.await,我会看到子进程仍在占用资源ps

问题:
如果时间已过 ,我如何才能持续一段时间await并执行操作await

注意:
我通过设置一个总是SIGKILL在两秒后发送的 tokio 计时器来解决我眼前的问题,并self.process.await在底部有一个计时器。但这种解决方案并不可取,因为当计时器运行时,另一个进程可能会在同一 PID 中生成。

编辑:
添加一个最小的、可重现的示例游乐场

error[E0382]: use of moved value: `self.process`
  --> src/bin/multi/process.rs:46:13
   |
42 |         if let Err(_) = tokio::time::timeout(std::time::Duration::from_secs(2), self.process).await
   |                                                                                 ------------ value moved here
...
46 |             self.process.await;
   |             ^^^^^^^^^^^^ value used here after move
   |
   = note: move occurs because `self.process` has type `tokio::process::Child`, which does not implement the `Copy` trait
Run Code Online (Sandbox Code Playgroud)

mgo*_*tIH 7

您需要传递一个可变引用。但是,您首先需要固定 future,以便其可变引用实现 Future。从future箱中重新导出的pin_mut是解决此问题的好帮手:

use futures::pin_mut;

async fn delay() {
    for _ in 0..6 {
        tokio::time::delay_for(std::time::Duration::from_millis(500)).await;
        println!("Ping!");
    }
}

async fn runner() {
    let delayer = delay();
    pin_mut!(delayer);
    if let Err(_) = tokio::time::timeout(std::time::Duration::from_secs(2), &mut delayer).await {
        println!("Taking more than two seconds");
        delayer.await;
    }
}
Run Code Online (Sandbox Code Playgroud)