Rust:一种线程崩溃处理机制研究
最近在研究 zkSync Era 的源码,看到了一种线程崩溃处理的方法,觉得可以借鉴。
thread_panic_notify.rs
1// Built-in deps
2// External uses
3use futures::{channel::mpsc, executor::block_on, SinkExt, StreamExt};
4use tokio::task::JoinHandle;
5// Local uses
6
7/// If its placed inside thread::spawn closure it will notify channel when this thread panics.
8pub struct ThreadPanicNotify(pub mpsc::Sender<bool>);
9
10impl Drop for ThreadPanicNotify {
11 fn drop(&mut self) {
12 if std::thread::panicking() {
13 block_on(self.0.send(true)).unwrap();
14 }
15 }
16}
17
18pub fn spawn_panic_handler() -> (JoinHandle<anyhow::Result<()>>, mpsc::Sender<bool>) {
19 let (panic_sender, mut panic_receiver) = mpsc::channel(1);
20
21 let handler = tokio::spawn(async move {
22 let _ = panic_receiver.next().await;
23 Ok(())
24 });
25 (handler, panic_sender)
26}
它定义了两个部分:
-
ThreadPanicNotify
结构体-
mpsc::Sender<bool>
字段,是一个多生产者单消费者(mpsc)通道的布尔值通道。 -
实现了
Drop
特征,当离开作用域时会自动执行。具体来说,它会检查当前的线程是否崩溃,如果是,用block_on
函数同步地向通道发送一个true
。
-
-
spawn_panic_handler
函数-
作用是创建一个可监听线程崩溃的异步任务。它首先创建了一个mpsc通道,然后用
tokio::spawn
函数启动了一个异步任务,等待从通道接收到一个值,然后返回一个Ok(())
结果。 -
返回这个异步任务的句柄(
JoinHandle<anyhow::Result<()>>
)和通道的发送端(mpsc::Sender<bool>
)。
-
下面是一个使用的例子:
main.rs
1mod thread_panic_notify;
2use anyhow::Ok;
3use thread_panic_notify::{spawn_panic_handler, ThreadPanicNotify};
4
5#[tokio::main]
6async fn main() -> anyhow::Result<()> {
7 // Get the handle of the asynchronous task and the sending end of the channel by calling the spawn_panic_handler function
8 let (handler, panic_sender) = spawn_panic_handler();
9
10 // Execute some code that may crash in a new thread
11 std::thread::spawn(move || {
12 // Create a ThreadPanicNotify structure and pass the sending end of the channel to it
13 let _panic_notify = ThreadPanicNotify(panic_sender);
14 panic!("ni hao")
15 });
16
17 // Wait for the asynchronous task to end
18 let _ = handler.await?;
19 Ok(())
20}
我们在创建线程时,将发送端传递给了ThreadPanicNotify
结构体,当线程崩溃时,ThreadPanicNotify
会自动向通道发送一个true
。