3个不稳定版本
0.2.0 | 2021年2月9日 |
---|---|
0.1.1 | 2021年2月9日 |
0.1.0 | 2021年2月6日 |
#937 in 游戏开发
25KB
289 行
panik-rs
此crate实现全应用范围内的panic处理,其中任何线程发生的panic都会被捕获并存储,之后可以查询以触发早期应用退出。
这与标准panic行为相反,在标准panic行为中,panic仅限于导致panic的线程。此库引入的条件是任何线程的panic都是错误,应用无法继续或恢复。
用例
此crate的主要用例是当一个线程创建了多个线程来执行工作,并在它们完成时阻塞。如果工作线程在结果发布之前panic,等待的线程可能会在recv
的阻塞调用中卡住,除非它专门计划和检查这种错误情况(例如,poisoned mutex,断开mpsc发送者)。
在一个大型应用中,如具有线程池和大量工作被提交的应用(如游戏引擎),正确处理每个panic情况可能很困难。使用此库允许主线程在其核心游戏循环中轮询panic,并优雅地退出,而不是在没有音频/渲染/AI/工作线程的情况下继续前进。
未使用panic检测且永久挂起的示例
let (tx, rx) = std::sync::mpsc::channel();
let worker = std::thread::spawn(move || {
// hopefully do some work...
// tx.send(5).unwrap();
// ...or panic and hold up the main thread forever
todo!()
});
let result: i32 = rx.recv().expect("recv failed"); // blocks forever
println!("result: {}", result);
检测和处理panic并优雅退出的相同示例
let application_result = panik::run_and_handle_panics(|| {
let (tx, rx) = std::sync::mpsc::channel();
let worker = std::thread::spawn(move || {
// do some work...
// tx.send(5).unwrap();
// ...or panic and hold up the main thread forever
todo!()
});
// periodically check if a panic has occurred
let poll_freq = Duration::from_secs(5);
while !panik::has_panicked() {
if let Ok(res) = rx.recv_timeout(poll_freq) {
return res;
}
}
// return value is irrelevant here, the panic on the worker
// thread will clobber this when `run_and_handle_panics`
// returns None
0
});
match application_result {
None => {
eprintln!("something went wrong: {:?}", panik::panics());
std::process::exit(1);
},
Some(result) => {
println!("result: {}", result);
std::process::exit(0);
}
}
这看起来相当重量级,但这是故意的 - 此库是为大型且重量级的应用而设计的!
功能
use-stderr
:将panic记录到stderruse-log
:使用log
crate记录panicuse-slog
:使用slog
crate记录panic(请参阅Builder::slogger
)use-parking-lot
:使用parking_lot::Mutex
代替std::sync::Mutex
依赖关系
~2.5–4MB
~77K SLoC