使用tokio::select!等待多信号时遇临时值被借用释放错误
在Tokio中同时监听SIGINT与SIGTERM的正确实现
在Tokio项目中尝试同时监听SIGTERM和SIGINT信号时,单独监听单个信号可正常运行:
tracing::debug!("Waiting for the end of the world"); signal(SignalKind::terminate())?.recv().await;
但使用tokio::select!同时监听两个信号时,会触发临时值在被借用时被释放的编译错误:
错误代码
use tokio::signal::unix::{signal, SignalKind}; tokio::select! { _ = signal(SignalKind::interrupt())?.recv() => println!("SIGINT"), _ = signal(SignalKind::terminate())?.recv() => println!("SIGTERM"), } println!("terminating the process...");
编译错误信息
error[E0716]: temporary value dropped while borrowed --> src/main.rs:495:13 | 494 | let ans = tokio::select! { | _______________- 495 | | _ = signal(SignalKind::interrupt())?.recv() => println!("SIGINT"), | | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ creates a temporary which is freed while still in use 496 | | _ = signal(SignalKind::terminate())?.recv() => println!("SIGTERM"), 497 | | }; | | - | | | | |_____temporary value is freed at the end of this statement | borrow might be used here, when `futures` is dropped and runs the destructor for type `(impl futures_util::Future<Output = std::option::Option<()>>, impl futures_util::Future<Output = std::option::Option<()>>)`
问题原因
signal()函数返回的Signal实例是临时值,recv()返回的Future会持有对该Signal的引用。当select!块执行结束时,临时Signal实例会被销毁,但Future可能仍在引用它,导致生命周期不匹配。
正确实现方式
提前创建并持有两个Signal实例,确保它们的生命周期覆盖整个select!执行过程:
use tokio::signal::unix::{signal, SignalKind}; // 提前创建信号监听器并持有所有权,延长生命周期 let mut sigint = signal(SignalKind::interrupt())?; let mut sigterm = signal(SignalKind::terminate())?; tokio::select! { _ = sigint.recv() => println!("SIGINT received"), _ = sigterm.recv() => println!("SIGTERM received"), } println!("terminating the process...");
说明
- 将
signal()返回的实例绑定到变量上,确保其生命周期足够长,直到select!执行完成 select!中调用recv()时,Future引用的是持久化的变量,不会出现临时值提前释放的问题
内容的提问来源于stack exchange,提问作者Simson
相关产品推荐
相关产品推荐

