Warning: file_get_contents(/data/phpspider/zhask/data//catemap/7/rust/4.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
什么';在Rust程序意外退出时,注册要运行的函数的最佳方法是什么?_Rust_Exit_Atexit - Fatal编程技术网

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

什么';在Rust程序意外退出时,注册要运行的函数的最佳方法是什么?,rust,exit,atexit,Rust,Exit,Atexit,我正在Rust中创建一个终端文本编辑器。编辑器将终端置于原始模式,禁用字符回显等,然后在退出时恢复原始终端功能 但是,编辑器有一些bug,并且由于诸如无符号变量下溢之类的问题而不时意外崩溃。发生这种情况时,将终端恢复到其原始状态的清理代码将永远不会运行 我要运行的清理功能如下所示: fn restore_orig_mode(editor_config: &EditorConfig) -> io::Result<()> { termios::tcsetattr(S

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

但是,编辑器有一些bug,并且由于诸如无符号变量下溢之类的问题而不时意外崩溃。发生这种情况时,将终端恢复到其原始状态的清理代码将永远不会运行

我要运行的清理功能如下所示:

fn restore_orig_mode(editor_config: &EditorConfig) -> io::Result<()> {
    termios::tcsetattr(STDIN, termios::TCSAFLUSH, &editor_config.orig_termios)
}
fn还原原始模式(编辑器配置:&EditorConfig)->io::结果{
termios::tcsetattr(STDIN、termios::TCSAFLUSH和editor\u config.orig\u termios)
}

试试看。我没用过,所以我不能保证它能用。

在最新的stable 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 { }
    }
}
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();
         }
    }
}
然后,为了调用
清理
,您必须管理对数据的访问,如下所示:

// 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 { }
    }
}
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之前,您只能处理子线程中发生的恐慌。除了需要克隆
之外,这没有什么不同,因为原始弧需要
移动到线程闭包中

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();
        }
    }
}

在Unix应用程序和使用C等其他语言时,解决此问题的一个常见方法是使用
fork()
并让您的家长等待孩子。在子级退出错误时,清除

如果清理工作很重要,这确实是唯一可靠的清理方法。例如,您的程序可能会被Linux OOM kill杀死。它永远无法运行特定于语言的死机、异常、at_退出或诸如此类的操作,因为操作系统只是简单地破坏了它

通过让一个单独的进程监视它,该进程可以处理文件或共享内存的任何特殊清理


此解决方案实际上不需要使用
fork()
。父级可以是一个shell脚本或一个单独的可执行文件。

与OP的要求不同。我认为它实际上可以解决OP的问题。你觉得怎么样@isaacg@Qix由“无符号变量下溢”引起的崩溃是由死机引起的,
catch\u unwind
可以处理死机。(文档警告说,这不会捕捉到中止进程的恐慌,但线程方法也不会捕捉到恐慌。)@1096年,我会说你的答案非常稀少。堆栈溢出(特别是在这里)强烈希望得到彻底、深入的答案。花点时间编写一些示例代码来证明您的想法(并允许您删除“不能保证”)会有很大帮助。进一步查看后,我发现这正是我想要的。您可以创建一个新线程来运行应用程序。主应用程序线程几乎没有任何可能出错的地方,如果子线程崩溃,它可以清理并重新启动子线程。我没有想过使用线程来完成这类事情,而不是并发。我一点也不打算接受,以防有更多的想法出现,但我尝试了这个方法,似乎效果很好。正如另一个答案所说,它允许避免线程。@Shepmaster“catch_unwind”是否有缺点?报告中提到,这对流产的恐慌不起作用。我不知道如何检查我的解决方案在那里是否有效,因为我不知道什么会导致流产性恐慌,而不是放松。@PeterHall-as,这两种解决方案都会失败。好消息是这个设置是由二进制作者设置的;由于OP正在制作一个编辑器,他们大概正在制作一个二进制文件,可以选择不设置该选项。螺纹答案的优点是在生锈1.9之前工作。否决票?我想我不该说“C”字。因为使用子流程确实是获得清理的唯一可靠方法。不幸的是,我们偶尔会得到海报完全忽略语言的答案。事实并非如此,因此我对其进行了一些编辑,以澄清您的解决方案与语言无关。然而,这个答案也相当稀少。指出实现解决方案的惯用代码(直接调用
fork
不是惯用代码),并解释为什么这是“唯一可靠的方法”,会有很大帮助。