rust - 在 tokio::time::timeout 之后再次等待 future

标签 rust async-await rust-tokio

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

它还负责在杀死 child 后释放资源,根据文档( std::process::Childtokio::process::Child ),这需要父级 wait() (或 await in tokio)的过程。

并非所有进程的行为都与 SIGINT 相同或 SIGTERM ,所以我想给 child 一些时间去死,然后我发送了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;
        }
    }

但是给出了这个错误:
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

如果我服从并删除 self.process.await , 我看到子进程仍在 ps 中占用资源.

问题:
我该怎么办 await一段时间并执行操作和 await再次如果时间到期?

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

编辑:
添加 minimal, reproducible example ( playground )

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();
    if let Err(_) = tokio::time::timeout(std::time::Duration::from_secs(2), delayer).await {
        println!("Taking more than two seconds");
        delayer.await;
    }
}

最佳答案

您需要传递一个可变引用。但是,您首先需要固定 future ,以便其可变引用实现 Future。 pin_mutfutures 重新导出crate 是一个很好的 helper :

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

关于rust - 在 tokio::time::timeout 之后再次等待 future ,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/61041856/

相关文章:

c# - 具有受控并行性和 AwaitAll 选项的异步任务

rust - GraphicsMagick FFI 问题

rust - 尝试在Wasm堆中保存字符串,然后将指向该字符串的指针保存在结构中时,使用“RuntimeError : Memory access out of bounds”

rust - 临时别名可变引用的最佳方法是什么?

c# - 在 ThreadPool 线程之间传递数据

c# - StaTaskScheduler 并等待继续

expression - 是println!表达或陈述?

timer - 如何使用 Tokio 产生许多可取消的计时器?

rust - 如何使用异步来并行化繁重的计算?

rust - Rust 单元测试错误 : "The async keyword is missing from the function declaration"