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