如何向 Rust 程序添加关闭挂钩?
How to add a shutdown hook to a Rust program?
我正在编写一个 Rust 程序,无论发生什么情况,它都需要在执行结束时保存一些数据。
在 Java 世界中,我会用 shutdown hook. There is a crate, aptly called shutdown_hooks 来做到这一点,但它似乎只能注册 extern "C"
函数(而且我不完全确定它会 运行 panic!(...)
).
我如何实现在正常退出时以及在紧急情况下触发的关闭挂钩?
一般情况下是不可能的。即使忽略程序外部的影响(如 ),编译最终二进制文件的人也可以选择恐慌是否真的触发堆栈展开,或者它是否只是中止程序。在后一种情况下,您无能为力。
在unwinding panic或者正常退出的情况下,可以执行Drop
and use the conventional aspects of RAII:
struct Cleanup;
impl Drop for Cleanup {
fn drop(&mut self) {
eprintln!("Doing some final cleanup");
}
}
fn main() {
let _cleanup = Cleanup;
panic!("Oh no!");
}
thread 'main' panicked at 'Oh no!', src/main.rs:12:5
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace.
Doing some final cleanup
看来 Java 的关闭挂钩允许 运行 多段代码在线程中并行。您可以通过一些小的修改来做类似的事情:
use std::{
sync::{Arc, Condvar, Mutex},
thread,
};
#[derive(Debug, Default)]
struct Cleanup {
hooks: Vec<thread::JoinHandle<()>>,
run: Arc<Mutex<bool>>,
go: Arc<Condvar>,
}
impl Cleanup {
fn add(&mut self, f: impl FnOnce() + Send + 'static) {
let run = self.run.clone();
let go = self.go.clone();
let t = thread::spawn(move || {
let mut run = run.lock().unwrap();
while !*run {
run = go.wait(run).unwrap();
}
f();
});
self.hooks.push(t);
}
}
impl Drop for Cleanup {
fn drop(&mut self) {
eprintln!("Starting final cleanup");
*self.run.lock().unwrap() = true;
self.go.notify_all();
for h in self.hooks.drain(..) {
h.join().unwrap();
}
eprintln!("Final cleanup complete");
}
}
fn main() {
let mut cleanup = Cleanup::default();
cleanup.add(|| {
eprintln!("Cleanup #1");
});
cleanup.add(|| {
eprintln!("Cleanup #2");
});
panic!("Oh no!");
}
另请参阅:
我正在编写一个 Rust 程序,无论发生什么情况,它都需要在执行结束时保存一些数据。
在 Java 世界中,我会用 shutdown hook. There is a crate, aptly called shutdown_hooks 来做到这一点,但它似乎只能注册 extern "C"
函数(而且我不完全确定它会 运行 panic!(...)
).
我如何实现在正常退出时以及在紧急情况下触发的关闭挂钩?
一般情况下是不可能的。即使忽略程序外部的影响(如
在unwinding panic或者正常退出的情况下,可以执行Drop
and use the conventional aspects of RAII:
struct Cleanup;
impl Drop for Cleanup {
fn drop(&mut self) {
eprintln!("Doing some final cleanup");
}
}
fn main() {
let _cleanup = Cleanup;
panic!("Oh no!");
}
thread 'main' panicked at 'Oh no!', src/main.rs:12:5
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace.
Doing some final cleanup
看来 Java 的关闭挂钩允许 运行 多段代码在线程中并行。您可以通过一些小的修改来做类似的事情:
use std::{
sync::{Arc, Condvar, Mutex},
thread,
};
#[derive(Debug, Default)]
struct Cleanup {
hooks: Vec<thread::JoinHandle<()>>,
run: Arc<Mutex<bool>>,
go: Arc<Condvar>,
}
impl Cleanup {
fn add(&mut self, f: impl FnOnce() + Send + 'static) {
let run = self.run.clone();
let go = self.go.clone();
let t = thread::spawn(move || {
let mut run = run.lock().unwrap();
while !*run {
run = go.wait(run).unwrap();
}
f();
});
self.hooks.push(t);
}
}
impl Drop for Cleanup {
fn drop(&mut self) {
eprintln!("Starting final cleanup");
*self.run.lock().unwrap() = true;
self.go.notify_all();
for h in self.hooks.drain(..) {
h.join().unwrap();
}
eprintln!("Final cleanup complete");
}
}
fn main() {
let mut cleanup = Cleanup::default();
cleanup.add(|| {
eprintln!("Cleanup #1");
});
cleanup.add(|| {
eprintln!("Cleanup #2");
});
panic!("Oh no!");
}
另请参阅: