我有一个Rust模块,它设置了一个具有crossbeam_channel:

fn sigint_channel() -> Result<Receiver<bool>, ctrlc::Error> {
    let (sender, receiver) = unbounded();

    // Handle Ctrl+C (aka SIGINT)
    ctrlc::set_handler(move || {
        warn!("Got SIGINT, stopping the Child ..");
        let _ = sender.send(true);
    })?;

    Ok(receiver)
}

然后,返回的Receiver被传递给模块函数,该模块函数运行系统命令Child并等待一些数据通过Channel:

if let Some(child) = get_child(cmd) {
    loop {
        select! {
            recv(receiver) -> _ => {
                kill(child);
                break;
            }
        }

        // Code never reached
        child.try_wait();
    }
}

现在,这项计划停滞不前,只能达到select!.即使子元素终止,代码仍在select!中等待.只有当我按下Ctrl+C时,程序才会退出.

我的 idea 是在父进程和子进程之间创建另一个通道,或者使用线程来运行子进程,但我不确定如何做到这一点.对如何实现这一点有什么 idea 吗?

我读到tokio它可以解决这个问题,但我不太理解它,因为我只有2个月的经验与铁 rust .

Edit

Childget_child()只是spawns a Command的函数,并返回Child对象.

我不能提供确切的代码,但最后一条指令是cmd.spawn(),要运行的系统命令是一个可能会花费太多时间的程序.因此,我需要随时按Ctrl+C或等待它自动退出.

推荐答案

我想你要找的东西是这样的:

loop {
    select! {
        // If we get the kill signal
        recv(receiver) -> _ => {
            // Kill child
            kill(child);
            break;
        }
        // Otherwise keep waiting for child to finish
        default(Duration::from_millis(100)) => {
            match child.try_wait() {
                Ok(Some(_)) => break,
                Ok(None) => (),
                Err(e) => panic!("error when waiting: {e}"),
            }
        }
    }
}

playground

Rust相关问答推荐

as操作符如何将enum转换为int?

捕获Rust因C++异常而产生panic

如何从polars DataFrame中获取一个列作为Option String?<>

无法从流中读取Redis请求

如何将映射反序列化为具有与键匹配的字段的定制 struct 的向量?

在文件链实施中绕过borrow 判断器

更合理的方法来设计样条线函数器?

为什么比较Option<;字符串>;具有常数Option<&;str>;需要显式类型转换吗?

为什么将易错函数的泛型结果作为泛型参数传递 infer ()?不应该是暧昧的吗?

Rust 重写函数参数

为什么 Rust 的临时值有时有参考性有时没有?

Rust 中的自动取消引用是如何工作的?

内部值发生变化时 Rc 的行为

打印 `format_args!` 时borrow 时临时值丢失

如何展平以下嵌套的 if let 和 if 语句?

n 个范围的笛卡尔积

如何在 use_effect_with_deps 中设置监听器内的状态?

为什么1..=100返回一个范围而不是一个整数?

通用函数中的生命周期扣除和borrow (通用测试需要)

将 (T, ()) 转换为 T 安全吗?