在Wasm出现恐慌后,如何触发Rust互斥锁的释放,以便将来的调用正常?

在Wasm出现恐慌后,如何触发Rust互斥锁的释放,以便将来的调用正常?,rust,webassembly,Rust,Webassembly,在使用Rust和WebAssembly进行开发时,我遇到了一个死锁 由于使用了一些全局访问的变量,我选择了lazy_static,而使用thread_本地回调的互斥将导致嵌套问题。我已经声明,JavaScript通过[wasm_bindgen]使用了很多Rust函数。他们读写静态变量 其中一个函数死机后,无法释放互斥锁,如果需要使用相同的互斥锁,则会导致其他函数死机 我知道恐慌问题是意外的,需要修复,但这些功能相对独立。尽管静态变量的读取和写入是相交的,但某个bug不一定会影响其他部分 在Was

在使用Rust和WebAssembly进行开发时,我遇到了一个死锁

由于使用了一些全局访问的变量,我选择了lazy_static,而使用thread_本地回调的互斥将导致嵌套问题。我已经声明,JavaScript通过[wasm_bindgen]使用了很多Rust函数。他们读写静态变量

其中一个函数死机后,无法释放互斥锁,如果需要使用相同的互斥锁,则会导致其他函数死机

我知道恐慌问题是意外的,需要修复,但这些功能相对独立。尽管静态变量的读取和写入是相交的,但某个bug不一定会影响其他部分

在Wasm中出现恐慌后,如何触发互斥锁的释放以允许其他调用正常?对于这类问题,有没有更好的做法

锈蚀:

使用std::sync::Mutex; 使用std::sync::TownError; 使用wasm_bindgen::prelude::*; 发布结构当前状态{ 发布索引:i32, } impl当前状态{ fn新->自我{ 当前状态{索引:1} } fn获取索引&mut self->i32{ 自指数+=1; self.index.clone } fn添加索引和多个自身{ 自指数+=2; } } 懒惰的人!{ pub static ref FOO:Mutex=Mutex::newCurrentStatus::new; } 当前状态{}的不安全impl发送 [瓦斯穆宾根] 发布fn添加索引{ 福洛克 .unwrap\u或\u elsepoison错误::进入\u内部 .加入"指数";; } [瓦斯穆宾根] 发布fn获取索引->i32{ 让mut foo=foo.lock.unwrap_或_elsePoisonError::into_inner; 如果foo.get_index==6{ 惊恐 } 返回foo.get_索引; } JavaScript:

const js=import../pkg/hello_wasm.js; js.thenjs=>{ window.js=js; console.logjs.get_索引; js.add_索引; console.logjs.get_索引; js.add_索引; console.logjs.get_索引; js.add_索引; console.logjs.get_索引; js.add_索引; console.logjs.get_索引; js.add_索引; };
在恐慌之后,我根本无法调用该函数,就好像Wasm已经死了一样。

在回答这个问题之前,我应该提到,恐慌处理不应该被用作一般的错误机制。它们应用于不可恢复的错误

引用

这允许程序立即终止,并向程序调用方提供反馈。惊恐应在程序达到不可恢复状态时使用

锈病的恐慌其实比最初出现在C++背景下的人要温和得多,我认为这是一些人在评论中写的情况。默认的锈锈恐慌终止线程,而C++异常终止整个进程。 引用

Rust中的致命逻辑错误会导致线程死机,在此期间,线程将展开堆栈,运行析构函数并释放所拥有的资源。虽然不是“try/catch”机制,但锈中的恐慌仍然可以被捕获,除非使用panic=abort和catch_展开并从中恢复编译,或者使用resume_展开恢复编译。如果没有捕获到死机,线程将退出,但是可以选择从具有join的不同线程检测死机。如果主线程死机而未捕获死机,则应用程序将以非零退出代码退出

从恐慌中恢复线程是可以的,但您应该知道,catch_unwind并不能保证抓住所有恐慌

请注意,此功能可能无法捕获锈病中的所有恐慌。Rust中的恐慌并不总是通过展开来实现,但也可以通过中止该过程来实现。此函数只捕获正在解除的恐慌,而不是那些中止该过程的恐慌

因此,我们明白从恐慌中恢复是好的。问题是锁中毒时该怎么办

引用

该模块中的互斥体实现了一种称为中毒的策略,即每当线程在持有互斥体时崩溃时,互斥体就会被视为中毒。一旦互斥体中毒,默认情况下,所有其他线程都无法访问该数据,因为它可能受到污染,某些不变量未得到支持

中毒是有原因的,因为数据的不变量可能无法保存。想想恐慌吧!在某个函数的中间。这只是一个额外的安全级别,您可以绕过它

但是,中毒的互斥锁不会阻止对底层数据的所有访问。毒物错误类型有一个into_内部方法,该方法将返回成功锁定时本应返回的保护。这允许访问数据,尽管锁已中毒

当然,修复panic总是比这样做更好。

在函数之一panic后,无法释放互斥锁的保持-您认为这是为什么?你试过什么
要检查这个吗?因为,据我所知,当持有锁的线程恐慌时,互斥锁会中毒。在这种情况下,您以后仍然可以使用互斥。你读过吗?这有帮助吗?或者你的问题有什么不同吗?你不应该真的从恐慌中恢复过来。恐慌不仅仅是像JS错误那样的温和异常,它是程序无法再运行了。@DenysSéguret我不知道这句话本身是否正确。是的,人们绝对不应该把恐慌当作预期的错误,也不应该把恐慌当作穷人的例外。但在很多情况下,从恐慌中恢复过来、重新启动流程、记录错误等等都是有意义的。@LukasKalbertodt I添加了一个例子
use std::sync::{Mutex, PoisonError};
fn main() {
    let mutex = Mutex::new(1);

    // We are prepared to face bugs if invariants are wrong
    println!("{}", mutex.lock().unwrap_or_else(PoisonError::into_inner));
}