rust 在时雄::time::timeout之后再次等待future

tv6aics1  于 2023-10-20  发布在  其他
关注(0)|答案(2)|浏览(118)

背景:

我有一个使用tokio::process的进程,它在时雄运行时中生成带有句柄的子进程。
它还负责在杀死子进程后释放资源,根据文档(std::process::Child,时雄::process::Child),这需要父进程为进程wait()(或时雄中的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。但是这种解决方案并不理想,因为当计时器运行时,另一个进程可能会在同一个PID中产生。

  • 编辑:*

添加minimal, reproducible exampleplayground

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

wfauudbj1#

你需要传递一个可变的引用。但是,您首先需要固定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;
    }
}
nom7f22z

nom7f22z2#

对于以下情况,可以重用通用 Package 器:

use std::time::Duration;
use futures::pin_mut;
use tokio::time::timeout;

pub async fn on_slow<T, S: FnOnce()>(
    future: impl Future<Output = T>,
    duration: Duration,
    fn_on_slow: S,
) -> T {
    pin_mut!(future);
    if let Ok(result) = timeout(duration, &mut future).await {
        result
    } else {
        fn_on_slow();
        future.await
    }
}

// usage
async fn runner() {
  on_slow(
    delay(), // some long running future WITHOUT .await
    Duration::from_secs(2),
    || println!("Taking more than two seconds")
  ).await
}

相关问题