在 Rust 程序意外退出期间注册要运行的函数的最佳方法是什么?

2024-05-07

我正在用 Rust 创建一个终端文本编辑器。编辑器将终端置于原始模式,禁用字符回显等,然后在退出时恢复原始终端功能。

然而,编辑器存在一些错误,并且由于无符号变量下溢等问题,时不时地意外崩溃。发生这种情况时,将终端恢复到原始状态的清理代码永远不会运行。

我想运行的清理功能如下:

fn restore_orig_mode(editor_config: &EditorConfig) -> io::Result<()> {
    termios::tcsetattr(STDIN, termios::TCSAFLUSH, &editor_config.orig_termios)
}

在最新的稳定 Rust 中,@for1096 的答案是最好的。在您的情况下,应用可能非常简单,因为您的清理不需要使用与应用程序代码共享的状态:

use std::panic::catch_unwind;

fn run_editor(){
    panic!("Error!");
    println!("Running!");
}

fn clean_up(){
    println!("Cleaning up!");
}

fn main(){
    match catch_unwind(|| run_editor()) {
        Ok(_) => println!("Exited successfully"),
        Err(_) =>  clean_up()
    }
}

如果您的清理需要访问与应用程序的共享状态,那么您将需要一些额外的机制来说服编译器它是安全的。例如,如果您的应用程序如下所示:

// The shared state of your application
struct Editor { /* ... */ }

impl Editor {
    fn run(&mut self){
        println!("running!");
        // panic!("Error!");
    }

    fn clean_up(&mut self){
        println!("cleaning up!");
    }

    fn new() -> Editor {
        Editor { }
    }
}

然后,为了调用clean_up,您必须管理对数据的访问,如下所示:

use std::panic::catch_unwind;
use std::sync::{Arc, Mutex};

fn main() {
    let editor = Arc::new(Mutex::new(Editor::new()));

    match catch_unwind(|| editor.lock().unwrap().run()) {
         Ok(_) => println!("Exited successfully"),
         Err(_) => {
             println!("Application panicked.");
             let mut editor = match editor.lock() {
                Ok(guard) => guard,
                Err(poisoned) => poisoned.into_inner(),
             };
             editor.clean_up();
         }
    }
}

在 Rust 1.9 之前,您只能处理子线程中发生的恐慌。这没有太大不同,只是您需要克隆Arc因为原来的那个需要moved 进入螺纹封闭。

use std::thread;
use std::sync::{Arc, Mutex};

fn main() {
    let editor = Arc::new(Mutex::new(Editor::new()));
    // clone before the original is moved into the thread closure
    let editor_recovery = editor.clone();

    let child = thread::spawn(move || {
         editor.lock().unwrap().run();
    });

    match child.join() {
        Ok(_) => println!("Exited successfully"),
        Err(_) => {
            println!("Application panicked.");
            let mut editor = match editor_recovery.lock() {
                Ok(guard) => guard,
                Err(poisoned) => poisoned.into_inner(),
            };
            editor.clean_up();
        }
    }
}
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

在 Rust 程序意外退出期间注册要运行的函数的最佳方法是什么? 的相关文章

随机推荐