【问题标题】:Await for future again after tokio::time::timeout在 tokio::time::timeout 之后再次等待未来
【发布时间】:2020-04-05 22:22:10
【问题描述】:

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

它还负责在杀死一个孩子后释放资源,根据文档(std::process::Childtokio::process::Child),这需要父进程wait()(或tokio中的await) .

并非所有进程对SIGINTSIGTERM 的行为都相同,所以我想在发送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 并在底部有一个self.process.await 的 tokio 计时器解决了我的直接问题。但是这种解决方案是不可取的,因为在计时器运行时可能会在同一个 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;
    }
}

【问题讨论】:

    标签: rust async-await rust-tokio


    【解决方案1】:

    您需要传递一个可变引用。但是,您首先需要固定 future 以使其可变引用实现 Future。 pin_mutfutures crate 重新导出是解决这个问题的好帮手:

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

    【讨论】:

    • 这是正确的! :) 另外,我能够避免把整个箱子都带进来,因为pin_mut 是一个相当简单的宏。我将链接添加到您的答案中,以便其他人更容易找到板条箱(以及宏的实现)
    猜你喜欢
    • 1970-01-01
    • 2016-01-22
    • 1970-01-01
    • 1970-01-01
    • 2020-08-11
    • 2015-12-09
    • 2019-08-14
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多