You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用Runtime::block_on时Tokio signal::ctrl_c触发panic求助

问题原因

手动通过Builder::new_multi_thread()创建的Tokio Runtime默认仅启用IO和时间驱动,未启用信号驱动(signal driver),而tokio::signal::ctrl_c()必须依赖信号驱动才能监听系统信号。相比之下,#[tokio::main]宏创建的Runtime默认会启用所有必要驱动(包括信号驱动),因此使用该宏时代码可正常运行。

解决方案

在构建Runtime时,显式调用enable_signal()方法启用信号驱动,或者使用enable_all()启用所有Runtime功能:

修改后的Runtime构建代码

let runtime = Builder::new_multi_thread()
    .worker_threads(2)
    .enable_signal() // 显式启用信号驱动
    .build().unwrap();

或者启用所有驱动:

let runtime = Builder::new_multi_thread()
    .worker_threads(2)
    .enable_all()
    .build().unwrap();

额外优化

代码中let _rt_guard = runtime.enter();是多余的,runtime.block_on()已经会将当前线程纳入Runtime的上下文环境,无需额外调用enter(),可以直接删除该语句。

修改后的完整代码
use tokio::runtime::Builder;
use tokio::signal;
use tokio::sync::watch;
use tokio::task::JoinSet;

fn main() {
    let runtime = Builder::new_multi_thread()
        .worker_threads(2)
        .enable_signal()
        .build().unwrap();
        
    runtime.block_on(async {
        let (ping_tx, mut ping_rx) = watch::channel(0u32);
        let (pong_tx, mut pong_rx) = watch::channel(0u32);
        let mut tasks = JoinSet::new();
        
        let ping = tasks.spawn(async move {
            let mut val = 0u32;
            ping_tx.send(val).unwrap();
            
            while val < 10u32 {
                pong_rx.changed().await.unwrap();
                val = *pong_rx.borrow();
                ping_tx.send(val + 1).unwrap();
                println!("ping! {}", val + 1);
            }
        });
        
        let pong = tasks.spawn(async move {
            let mut val = 0u32;
            
            while val < 10u32 {
                ping_rx.changed().await.unwrap();
                val = *ping_rx.borrow();
                pong_tx.send(val + 1).unwrap();
                println!("pong! {}", val + 1);
            }
        });
        
        let mut interrupt = Box::pin(signal::ctrl_c());
        let mut interrupt_read = false;
        
        while !interrupt_read && !tasks.is_empty() {
            tokio::select! {
                biased;
                _ = &mut interrupt, if !interrupt_read => {
                    ping.abort();
                    pong.abort();
                    interrupt_read = true;
                },
                _ = tasks.join_next() => {}
            }
        }
    });
}

内容的提问来源于stack exchange,提问作者hal7df

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.31 23:50:35